JAVA FOUNDATIONS · JAVA 17
Java interfaces: swap a formatter without changing the caller
Implement a small interface using ordinary named classes and pass different implementations to the same method.
Forsk Coding School learning resources · Updated 2026-10-26
What you will learn
- Define a contract through an interface
- Implement the same operation in two classes
- Use a parameter typed to the interface
Before you start: Classes, objects, constructors and instance methods.
Describe the operation the caller needs
A caller that prints a greeting needs a formatter: something that can turn a name into a message. It does not need to know how every formatting style works. The Greeting interface declares that operation. FriendlyGreeting and FormalGreeting provide different implementations, and show accepts either implementation through the same parameter type.
The example uses named classes rather than a lambda. That keeps the contract, implementation and call site visible as separate pieces. An interface is not an object by itself. new FriendlyGreeting() constructs a concrete implementation that can be assigned to a Greeting variable.
Follow the dependency through the method parameter
show does not construct a particular formatter internally. The caller supplies one. This makes the choice explicit at the point where the program is assembled. It also makes a test simple: pass a known implementation and compare the returned message. You do not need a dependency-injection framework to understand or use this basic design.
An implementation of this interface method must be public. The contract declared in the interface is public, so an implementing class cannot narrow its access. @Override checks that the method name, parameter types and return type satisfy that contract. Parameter variable names can differ; the signature still has to describe the same operation.
Choose a useful abstraction boundary
Keep the interface focused on something the caller actually needs. Adding unrelated operations forces every implementation to deal with responsibilities it may not have. Here one format operation is enough. If a future formatter needs configuration, provide that through its constructor while keeping the caller's use of format stable.
An interface gives a shared type, not a promise that every implementation is correct or side-effect-free. Describe expectations such as handling a null or blank name and test them consistently. This demonstration supplies non-null names and only returns text. It deliberately keeps validation policy separate from the mechanism used to substitute implementations.
Run the worked example
Save as Main.java. Run javac Main.java, then java Main.
interface Greeting {
String format(String name);
}
class FriendlyGreeting implements Greeting {
@Override public String format(String name) { return "Hi " + name; }
}
class FormalGreeting implements Greeting {
@Override public String format(String name) { return "Welcome, " + name; }
}
public class Main {
static void show(Greeting greeting, String name) {
System.out.println(greeting.format(name));
}
public static void main(String[] args) {
show(new FriendlyGreeting(), "Asha");
show(new FormalGreeting(), "Asha");
}
}Expected result
Hi Asha
Welcome, Asha- Both classes implement the same format(String) operation.
- show receives a Greeting reference and delegates the formatting decision.
- Changing the supplied object changes output without editing show.
Common mistakes to check
- Use implements for a class implementing an interface.
- Do not omit public on the implementing method.
- Separate creating an implementation from calling a method on the interface.
Try it yourself
Define an Operation interface with int apply(int value). Implement DoubleValue and TripleValue and print their results for 4 through Operation references.
Give me a hint
Use named implementing classes and public methods. No lambda is required.
Compare with one working solution
interface Operation { int apply(int value); }
class DoubleValue implements Operation {
@Override public int apply(int value) { return value * 2; }
}
class TripleValue implements Operation {
@Override public int apply(int value) { return value * 3; }
}
public class Main {
public static void main(String[] args) {
for (Operation item : new Operation[]{new DoubleValue(), new TripleValue()}) {
System.out.println(item.apply(4));
}
}
}Expected result
8
12Quick check
Choose an answer, then check the explanation. Your answer stays in this page and is not saved as a student record.
Keep learning
Explain the result in your own words, change one input and predict the new output. For additional structured assignments, explore the workbook sample before requesting the full pack.
Explore the practice workbookReference documentation
Use the official reference to check language details. The explanations, examples and exercises on this page are written for this learning resource.
