An interface defines a contract that an implementation agrees to provide.
Java interfaces and replaceable behavior
Working model
Declare the capability a caller needs. A job service can depend on a notification contract without committing to email transport, vendor-specific APIs, or a console implementation.
Code
public class JobNotifier {
interface NotificationChannel {
void send(String message);
}
static class ConsoleChannel implements NotificationChannel {
public void send(String message) {
System.out.println(message);
}
}
public static void main(String[] args) {
NotificationChannel channel = new ConsoleChannel();
channel.send("Job JOB-42 completed");
}
}The output is Job JOB-42 completed. A production transport would define failure handling, timeouts, and delivery semantics. The interface does not supply those guarantees by itself.
Cost and design choices
Keep contracts narrow. A method that needs only send should not require unrelated administration methods. Interfaces can reduce coupling, but an excessive number of tiny contracts can hide the actual flow of work.
Default methods still need conflict rules
An interface can provide a default instance method, but that does not give it per-instance field storage. If unrelated interfaces supply conflicting defaults, an implementing class may need to resolve the conflict explicitly.
A method signature is only part of a contract. Document null handling, ownership, side effects, and any required performance bound. Two implementations with the same signature can still behave incompatibly when those rules differ.
Connected lessons
Continue with Methods and objects, Java Tutorial.
Common Mistakes
An interface reference can still be null. Do not suppress transport failures and report success. Specify whether repeated calls can deliver duplicate notifications.
Describe behavior without promising an implementation
An interface names the operations and behavior a caller can require. List and Deque expose different permitted actions even when LinkedList implements both. Choose the narrower contract that actually represents the caller’s requirement rather than publishing every available method.
A default method can share behavior but does not automatically add object state or resolve every multiple-interface conflict. A class combining conflicting defaults must choose an implementation explicitly. Static interface methods also do not become ordinary virtual instance methods.
Thread safety, ownership and cost still depend on the chosen implementation and its documented contract. Accepting a List parameter does not imply constant-time indexing, immutable membership or safe concurrent traversal. If an algorithm needs one of those properties, state it or change the representation.
Apply this contract in Spring
Spring constructor injection: required dependencies stay visible, Spring qualifiers: select a collaborator when types are ambiguous. These lessons keep framework assembly separate from the Java contract.
Extend this boundary
Continue with Spring method authorization: test the proxied service boundary.
Extend the tested workflow
Continue with Spring Data JPA repositories: derive a query from mapped properties.
