Interfaces in Java
Learn Interfaces in Java in detail, including interface declaration, implementation, multiple interfaces, default methods, static methods, private methods, functional interfaces, polymorphism, and practical examples.
Introduction
An interface is one of the most important tools for abstraction and flexible object-oriented design in Java. It defines a contract that implementing classes agree to follow.
interface Payment {
void pay(double amount);
}
class UPIPayment
implements Payment {
@Override
public void pay(double amount) {
System.out.println(
"Paid ₹"
+ amount
+ " using UPI"
);
}
}The Payment interface defines what a payment implementation must do. The UPIPayment class decides how the payment operation is performed.
- What an interface is.
- Why interfaces are useful.
- How to declare interfaces.
- How classes implement interfaces.
- How interface methods work.
- How interface fields work.
- Rules of interfaces.
- How interface references work.
- How interfaces support polymorphism.
- How multiple implementations work.
- How a class implements multiple interfaces.
- How interfaces provide multiple inheritance of type.
- How one interface extends another.
- How default methods work.
- How default method conflicts are resolved.
- How static methods work in interfaces.
- How private methods work in interfaces.
- What marker interfaces are.
- What functional interfaces are.
- How lambda expressions work with interfaces.
- How method references work.
- How built-in functional interfaces work.
- How interfaces support dependency injection.
- How interfaces reduce coupling.
- What interface segregation means.
- How composition works with interfaces.
- What nested interfaces are.
- What sealed interfaces are.
- The difference between interfaces and abstract classes.
- When interfaces should and should not be used.
What is an Interface?
An interface is a reference type that defines a contract. It specifies behavior that implementing classes must provide, while allowing each class to use its own implementation.
INTERFACE
Payment
pay()
│
┌──────────┼──────────┐
│ │ │
▼ ▼ ▼
CreditCard UPI Wallet
│ │ │
▼ ▼ ▼
Card Logic UPI Logic Wallet Logic- An interface defines a contract.
- It describes required behavior.
- Different classes can implement the same contract differently.
- Calling code can depend on the interface instead of a concrete class.
- One interface can represent many implementations.
Why Use Interfaces?
Abstraction
Interfaces expose required behavior without exposing implementation details.
Loose Coupling
Classes can depend on contracts instead of specific implementations.
Polymorphism
One interface reference can represent many implementation objects.
Extensibility
New implementations can be added without changing stable calling code.
Multiple Types
A class can implement multiple interfaces.
Testability
Real implementations can be replaced with test implementations.
Real-World Analogy
A charging standard defines a contract between a charger and a device. Different manufacturers can create different internal implementations as long as they follow the same required connection standard.
CHARGING STANDARD
connect()
│
┌───────────┼───────────┐
│ │ │
▼ ▼ ▼
Phone Tablet Laptop
│ │ │
▼ ▼ ▼
Different Different Different
Hardware Hardware HardwareThe interface acts like the standard. Implementing classes may work differently internally but must follow the same contract.
Interface Syntax
interface InterfaceName {
// Constants
// Abstract methods
// Default methods
// Static methods
// Private methods
}interface Printable {
void print();
}Basic Interface Example
public interface Animal {
void sound();
}public class Dog
implements Animal {
@Override
public void sound() {
System.out.println(
"Dog barks"
);
}
}public class Main {
public static void main(
String[] args
) {
Animal animal =
new Dog();
animal.sound();
}
}Dog barksImplementing an Interface
A class uses the implements keyword to follow an interface contract.
class ClassName
implements InterfaceName {
@Override
public void requiredMethod() {
// Implementation
}
}INTERFACE
Printable
│
│ implemented by
▼
CLASS
Document
│
▼
Provides print()Interface Methods
A traditional interface method declared without a body is implicitly public and abstract.
interface Payment {
void pay(double amount);
}
interface Payment {
public abstract void pay(
double amount
);
}- Abstract interface methods are public.
- Implementing methods must also be public.
- Reducing visibility causes a compilation error.
- The public abstract modifiers are usually omitted because they are implicit.
Interface Fields
Every field declared in an interface is implicitly public, static, and final. Interface fields are constants.
interface Configuration {
int MAX_RETRIES = 3;
}interface Configuration {
public static final int
MAX_RETRIES = 3;
}System.out.println(
Configuration.MAX_RETRIES
);Rules of Interfaces
- An interface is declared using the interface keyword.
- An interface cannot be instantiated directly.
- An interface can be used as a reference type.
- Abstract interface methods are implicitly public and abstract.
- Interface fields are implicitly public, static, and final.
- An interface does not have normal instance constructors.
- An interface cannot contain normal instance fields.
- An interface can contain default methods.
- An interface can contain static methods.
- An interface can contain private methods.
- An interface can contain private static methods.
- A class uses implements to implement an interface.
- A class can implement multiple interfaces.
- An interface can extend another interface.
- An interface can extend multiple interfaces.
- A concrete class must implement all required abstract methods.
Interface Implementation Rules
- Use the implements keyword.
- Implement all inherited abstract methods in a concrete class.
- Use public visibility for implemented interface methods.
- Use @Override for implemented methods.
- An abstract class may leave interface methods unimplemented.
- A class may implement multiple interfaces.
- One method can satisfy identical method contracts from multiple interfaces.
- Conflicting default methods must be resolved explicitly.
- A superclass method takes priority over an interface default method.
Cannot Create Interface Objects
interface Payment {
}
Payment payment =
new Payment();
// Compilation errorAn interface defines a contract rather than a complete object implementation, so it cannot be instantiated directly.
Interface References
An interface can be used as a reference type for objects of implementing classes.
Payment payment =
new UPIPayment();
payment.pay(5000);Payment payment = new UPIPayment();
│ │
▼ ▼
Interface Type Object Type
Accessible Members
Controlled by Payment
Method Implementation
Controlled by UPIPaymentInterfaces and Polymorphism
Payment payment;
payment =
new CreditCardPayment();
payment.pay(5000);
payment =
new UPIPayment();
payment.pay(2500);
payment =
new WalletPayment();
payment.pay(1000);The same Payment reference represents different implementation objects. The correct implementation is selected at runtime.
Multiple Implementations
interface Payment {
void pay(double amount);
}class CardPayment
implements Payment {
@Override
public void pay(double amount) {
System.out.println(
"Card payment: ₹"
+ amount
);
}
}class UPIPayment
implements Payment {
@Override
public void pay(double amount) {
System.out.println(
"UPI payment: ₹"
+ amount
);
}
}- Calling code depends on Payment.
- Implementations can change independently.
- New payment methods can be added.
- Existing calling code often remains unchanged.
- Implementations can be replaced during testing.
Implementing Multiple Interfaces
A Java class can implement more than one interface.
interface Printable {
void print();
}
interface Scannable {
void scan();
}class MultiFunctionPrinter
implements Printable,
Scannable {
@Override
public void print() {
System.out.println(
"Printing"
);
}
@Override
public void scan() {
System.out.println(
"Scanning"
);
}
}Multiple Inheritance with Interfaces
Java does not allow a class to extend multiple classes, but a class can implement multiple interfaces.
Printable Scannable
\ /
\ /
▼ ▼
MultiFunctionPrinterclass SmartDevice
implements Connectable,
Rechargeable,
Updatable {
// Implement all required methods
}Interface Extending Interface
interface Animal {
void eat();
}interface Pet extends Animal {
void play();
}class Dog implements Pet {
@Override
public void eat() {
System.out.println(
"Dog eats"
);
}
@Override
public void play() {
System.out.println(
"Dog plays"
);
}
}Multiple Interface Inheritance
Unlike classes, an interface can extend multiple interfaces.
interface Printable {
void print();
}
interface Scannable {
void scan();
}
interface AdvancedDevice
extends Printable,
Scannable {
void connect();
}Default Methods
A default method is an interface method with an implementation. It is declared using the default keyword.
interface Payment {
void pay(double amount);
default void printReceipt() {
System.out.println(
"Receipt generated"
);
}
}class UPIPayment
implements Payment {
@Override
public void pay(double amount) {
System.out.println(
"UPI payment completed"
);
}
}
UPIPayment payment =
new UPIPayment();
payment.printReceipt();- They allow interfaces to add behavior.
- Existing implementations do not always need to change.
- They support interface evolution.
- They provide optional shared behavior.
- Implementing classes can override them.
Overriding Default Methods
interface Payment {
default void printReceipt() {
System.out.println(
"Standard receipt"
);
}
}
class CardPayment
implements Payment {
@Override
public void printReceipt() {
System.out.println(
"Detailed card receipt"
);
}
}Default Method Conflicts
interface Camera {
default void start() {
System.out.println(
"Camera started"
);
}
}
interface MusicPlayer {
default void start() {
System.out.println(
"Music started"
);
}
}class Smartphone
implements Camera,
MusicPlayer {
// Must resolve start() conflict
}Resolving Default Method Conflicts
class Smartphone
implements Camera,
MusicPlayer {
@Override
public void start() {
System.out.println(
"Smartphone started"
);
}
}class Smartphone
implements Camera,
MusicPlayer {
@Override
public void start() {
Camera.super.start();
MusicPlayer.super.start();
}
}Class Method vs Interface Default Method
When a superclass method and an interface default method have the same compatible signature, the class method takes priority.
class Parent {
public void show() {
System.out.println(
"Parent method"
);
}
}
interface Displayable {
default void show() {
System.out.println(
"Interface method"
);
}
}
class Child
extends Parent
implements Displayable {
}CLASS METHOD
takes priority over
INTERFACE DEFAULT METHODStatic Methods in Interfaces
interface Validator {
static boolean isValid(
String value
) {
return value != null
&& !value.isBlank();
}
}boolean valid =
Validator.isValid(
"Java"
);- Static interface methods belong to the interface.
- They are called using the interface name.
- They are not inherited as instance methods.
- They cannot be overridden through runtime polymorphism.
Private Methods in Interfaces
Private interface methods allow shared internal logic to be reused by default methods without exposing that logic to implementing classes.
interface Logger {
default void logInfo(
String message
) {
log(
"INFO",
message
);
}
default void logError(
String message
) {
log(
"ERROR",
message
);
}
private void log(
String level,
String message
) {
System.out.println(
level
+ ": "
+ message
);
}
}Private Static Methods
interface TextUtility {
static String clean(
String value
) {
return normalize(value);
}
private static String normalize(
String value
) {
return value == null
? ""
: value.trim();
}
}Types of Methods in Interfaces
INTERFACE METHODS
├── Abstract Methods
│
│ No body
│ public abstract
│
├── Default Methods
│
│ Have body
│ Inherited by implementations
│
├── Static Methods
│
│ Have body
│ Belong to interface
│
├── Private Methods
│
│ Have body
│ Internal instance helpers
│
└── Private Static Methods
Have body
Internal static helpersConstants in Interfaces
interface ApplicationConfig {
String APP_NAME =
"PrograMinds";
int MAX_USERS =
1000;
}Interface fields should generally represent true constants related to the interface contract. Interfaces should not be used merely as containers for unrelated constants.
Marker Interfaces
A marker interface contains no methods or fields. It marks a class as having a particular characteristic.
interface Auditable {
}
class Transaction
implements Auditable {
}- Serializable marks objects that can participate in Java serialization.
- Cloneable is associated with object cloning behavior.
- Custom marker interfaces can identify special categories of application objects.
Functional Interfaces
A functional interface has exactly one abstract method. It can be used with lambda expressions and method references.
interface Calculator {
int calculate(
int a,
int b
);
}Calculator addition =
(a, b) -> a + b;
int result =
addition.calculate(
10,
20
);@FunctionalInterface
@FunctionalInterface
interface Greeting {
void greet(String name);
}- It documents the intended purpose.
- The compiler verifies that only one abstract method exists.
- It prevents accidental changes that break lambda compatibility.
- It improves API clarity.
Lambda Expressions
Greeting greeting =
new Greeting() {
@Override
public void greet(
String name
) {
System.out.println(
"Hello "
+ name
);
}
};Greeting greeting =
name ->
System.out.println(
"Hello " + name
);The lambda provides the implementation of the single abstract method without creating a named implementation class.
Method References
Greeting greeting =
System.out::println;
greeting.greet(
"Welcome to Java"
);Static Method
ClassName::staticMethod
Instance Method of Object
object::instanceMethod
Instance Method of Type
ClassName::instanceMethod
Constructor
ClassName::newBuilt-in Functional Interfaces
Java provides commonly used functional interfaces in the java.util.function package.
Predicate<T>
T → boolean
Function<T, R>
T → R
Consumer<T>
T → no result
Supplier<T>
no input → TPredicate
Predicate<Integer> isAdult =
age -> age >= 18;
System.out.println(
isAdult.test(25)
);Function
Function<String, Integer>
lengthCalculator =
text -> text.length();
int length =
lengthCalculator.apply(
"Java"
);Consumer
Consumer<String> printer =
message ->
System.out.println(
message
);
printer.accept(
"Hello Java"
);Supplier
Supplier<Double>
randomNumber =
() -> Math.random();
double value =
randomNumber.get();Interface as Method Parameter
static void processPayment(
Payment payment,
double amount
) {
payment.pay(amount);
}processPayment(
new CardPayment(),
5000
);
processPayment(
new UPIPayment(),
2500
);Interface as Return Type
static Payment createPayment(
String type
) {
if (type.equals("upi")) {
return new UPIPayment();
}
return new CardPayment();
}Payment payment =
createPayment("upi");
payment.pay(5000);Interface Arrays
Payment[] payments = {
new CardPayment(),
new UPIPayment(),
new WalletPayment()
};for (Payment payment : payments) {
payment.pay(1000);
}Interface Collections
List<Payment> payments =
new ArrayList<>();
payments.add(
new CardPayment()
);
payments.add(
new UPIPayment()
);
for (Payment payment : payments) {
payment.pay(1000);
}Interfaces and Dependency Injection
interface PaymentGateway {
boolean process(
double amount
);
}class OrderService {
private final PaymentGateway
paymentGateway;
OrderService(
PaymentGateway
paymentGateway
) {
this.paymentGateway =
paymentGateway;
}
void checkout(
double amount
) {
paymentGateway.process(
amount
);
}
}OrderService orderService =
new OrderService(
new UPIPaymentGateway()
);- OrderService depends on an interface.
- The implementation is supplied from outside.
- Implementations can be replaced.
- Testing becomes easier.
- This approach is widely used in Spring applications.
Loose Coupling with Interfaces
OrderService
│
▼
UPIPaymentGateway
OrderService directly depends
on one concrete classOrderService
│
▼
PaymentGateway Interface
│
┌──┼──┐
│ │ │
▼ ▼ ▼
Card UPI WalletInterface Segregation
Interface segregation means creating small, focused interfaces instead of forcing classes to implement methods they do not need.
interface Worker {
void work();
void eat();
void sleep();
}interface Workable {
void work();
}
interface Eatable {
void eat();
}
interface Sleepable {
void sleep();
}- Keep interfaces small.
- Keep interfaces focused.
- Do not force implementations to depend on unused methods.
- Combine multiple focused interfaces when required.
Composition with Interfaces
interface Engine {
void start();
}class Car {
private final Engine engine;
Car(Engine engine) {
this.engine = engine;
}
void start() {
engine.start();
}
}The Car does not inherit from an engine. It contains an Engine dependency. Different engine implementations can be supplied without changing the Car class.
Nested Interfaces
class Application {
interface Listener {
void onEvent();
}
}class EventHandler
implements Application.Listener {
@Override
public void onEvent() {
System.out.println(
"Event received"
);
}
}Sealed Interfaces
A sealed interface restricts which classes or interfaces are allowed to implement or extend it.
sealed interface Payment
permits CardPayment,
UPIPayment {
}final class CardPayment
implements Payment {
}
final class UPIPayment
implements Payment {
}- Control the permitted implementation hierarchy.
- Model a fixed set of alternatives.
- Improve exhaustive type handling.
- Make domain models more explicit.
Interface vs Abstract Class
INTERFACE
Defines a contract
Class can implement multiple
No normal instance state
No constructors
Supports default methods
Supports static methods
Supports private helper methods
Best for capabilities and contracts
ABSTRACT CLASS
Defines a base class
Class can extend only one
Can contain instance state
Can have constructors
Can contain abstract methods
Can contain concrete methods
Best for closely related classes
sharing state and behaviorInterface vs Class
INTERFACE
Defines required behavior
Cannot be instantiated directly
No normal object state
Implemented using implements
Can extend multiple interfaces
CLASS
Defines state and behavior
Can create objects if concrete
Can contain instance fields
Extended using extends
Can extend only one classWhen to Use Interfaces
- When different classes share a common capability.
- When calling code should depend on a contract.
- When multiple implementations are expected.
- When implementations may change.
- When dependency injection is used.
- When testing requires replaceable implementations.
- When a class needs multiple types.
- When unrelated classes need common behavior.
- When API boundaries should remain stable.
- When loose coupling is important.
When to Avoid Interfaces
- When only one simple implementation exists and no abstraction is useful.
- When the interface merely duplicates a concrete class.
- When shared mutable state is required.
- When implementations are tightly related and share substantial code.
- When an abstract class better represents the hierarchy.
- When an interface is created only for unnecessary architectural layers.
- When the contract is unstable and poorly understood.
Payment Example
public interface Payment {
boolean pay(double amount);
default void printReceipt(
double amount
) {
System.out.println(
"Receipt amount: ₹"
+ amount
);
}
}public class CreditCardPayment
implements Payment {
@Override
public boolean pay(
double amount
) {
if (amount <= 0) {
return false;
}
System.out.println(
"Credit card payment: ₹"
+ amount
);
return true;
}
}public class UPIPayment
implements Payment {
@Override
public boolean pay(
double amount
) {
if (amount <= 0) {
return false;
}
System.out.println(
"UPI payment: ₹"
+ amount
);
return true;
}
}public class CheckoutService {
private final Payment payment;
public CheckoutService(
Payment payment
) {
this.payment = payment;
}
public void checkout(
double amount
) {
if (payment.pay(amount)) {
payment.printReceipt(
amount
);
}
}
}Notification Example
public interface NotificationService {
void send(
String recipient,
String message
);
}public class EmailNotification
implements NotificationService {
@Override
public void send(
String recipient,
String message
) {
System.out.println(
"Email sent to "
+ recipient
);
}
}public class SMSNotification
implements NotificationService {
@Override
public void send(
String recipient,
String message
) {
System.out.println(
"SMS sent to "
+ recipient
);
}
}public class NotificationManager {
private final NotificationService
notificationService;
public NotificationManager(
NotificationService service
) {
this.notificationService =
service;
}
public void notifyUser(
String recipient,
String message
) {
notificationService.send(
recipient,
message
);
}
}Repository Example
public interface UserRepository {
void save(User user);
User findById(long id);
void delete(long id);
}public class DatabaseUserRepository
implements UserRepository {
@Override
public void save(User user) {
System.out.println(
"Saving user to database"
);
}
@Override
public User findById(long id) {
System.out.println(
"Finding user in database"
);
return null;
}
@Override
public void delete(long id) {
System.out.println(
"Deleting user from database"
);
}
}public class UserService {
private final UserRepository
userRepository;
public UserService(
UserRepository
userRepository
) {
this.userRepository =
userRepository;
}
public void register(
User user
) {
userRepository.save(user);
}
}Authentication Example
public interface
AuthenticationProvider {
boolean authenticate(
String username,
String password
);
}public class DatabaseAuthentication
implements AuthenticationProvider {
@Override
public boolean authenticate(
String username,
String password
) {
System.out.println(
"Checking database"
);
return true;
}
}public class AuthenticationService {
private final AuthenticationProvider
provider;
public AuthenticationService(
AuthenticationProvider provider
) {
this.provider = provider;
}
public boolean login(
String username,
String password
) {
return provider.authenticate(
username,
password
);
}
}Storage Example
public interface Storage {
void save(
String filename,
byte[] data
);
byte[] load(
String filename
);
}public class LocalStorage
implements Storage {
@Override
public void save(
String filename,
byte[] data
) {
System.out.println(
"Saving locally: "
+ filename
);
}
@Override
public byte[] load(
String filename
) {
System.out.println(
"Loading locally: "
+ filename
);
return new byte[0];
}
}public class CloudStorage
implements Storage {
@Override
public void save(
String filename,
byte[] data
) {
System.out.println(
"Uploading to cloud: "
+ filename
);
}
@Override
public byte[] load(
String filename
) {
System.out.println(
"Downloading from cloud: "
+ filename
);
return new byte[0];
}
}Common Interface Errors
INTERFACE ERRORS
├── Trying to Instantiate an Interface
├── Forgetting the implements Keyword
├── Using extends Instead of implements
├── Not Implementing Required Methods
├── Forgetting public Visibility
├── Reducing Method Visibility
├── Changing the Method Signature
├── Forgetting @Override
├── Trying to Create Interface Constructors
├── Creating Normal Instance Fields
├── Modifying Interface Constants
├── Assuming Interface Fields Are Mutable
├── Confusing Interface with Abstract Class
├── Assuming Interfaces Cannot Have Method Bodies
├── Forgetting Default Methods
├── Forgetting Static Methods
├── Forgetting Private Methods
├── Calling Static Methods Through Objects
├── Trying to Override Static Interface Methods
├── Ignoring Default Method Conflicts
├── Not Resolving Diamond Conflicts
├── Forgetting Class Methods Take Priority
├── Creating Large God Interfaces
├── Violating Interface Segregation
├── Forcing Unused Methods on Implementations
├── Creating One Interface per Class Without Purpose
├── Creating Interfaces Only for Extra Layers
├── Depending on Concrete Classes
├── Using instanceof Instead of Polymorphism
├── Excessive Downcasting
├── Leaking Implementation Details
├── Returning Concrete Types Unnecessarily
├── Accepting Concrete Parameters Unnecessarily
├── Misusing Marker Interfaces
├── Forgetting @FunctionalInterface
├── Adding a Second Abstract Method to Functional Interface
├── Confusing Default Methods with Abstract Methods
├── Confusing Lambda Expressions with Normal Objects
├── Using Wrong Functional Interface
├── Ignoring Generic Types
├── Creating Ambiguous Default Methods
├── Overusing Default Methods
├── Storing Unrelated Constants in Interfaces
├── Unstable Interface Contracts
├── Breaking Existing Implementations
├── Poor Method Naming
├── Poor Contract Documentation
├── Overly Broad Interfaces
├── Tight Coupling Between Interfaces
├── Deep Interface Hierarchies
├── Ignoring Composition
└── Abstracting Without a Real NeedBest Practices
- Use interfaces to define clear contracts.
- Program to interfaces instead of implementations.
- Keep interfaces small and focused.
- Follow the Interface Segregation Principle.
- Use meaningful interface names.
- Define behavior rather than implementation details.
- Avoid exposing concrete implementation types.
- Use interface types for method parameters.
- Use interface types for return values when appropriate.
- Use interface types for fields and dependencies.
- Use constructor injection for required dependencies.
- Provide implementations from outside dependent classes.
- Use interfaces to reduce coupling.
- Use interfaces when multiple implementations are expected.
- Use interfaces for replaceable infrastructure.
- Use interfaces for external service boundaries.
- Use interfaces to improve testability.
- Create test implementations when useful.
- Use @Override for implemented methods.
- Use @FunctionalInterface for intended functional interfaces.
- Keep functional interfaces limited to one abstract method.
- Use built-in functional interfaces when they clearly fit.
- Avoid creating unnecessary custom functional interfaces.
- Use default methods carefully.
- Do not place large amounts of business logic in default methods.
- Use default methods mainly for compatible evolution and useful shared behavior.
- Resolve default method conflicts explicitly.
- Remember that class methods take priority over default methods.
- Call static interface methods through the interface name.
- Use private interface methods for shared internal default-method logic.
- Use constants only when they belong to the contract.
- Avoid constant-only interfaces.
- Use multiple focused interfaces instead of one large interface.
- Use composition with interfaces for replaceable behavior.
- Prefer capability-based interface names.
- Document method expectations.
- Document valid inputs.
- Document return-value meaning.
- Document expected exceptions.
- Keep contracts stable.
- Avoid breaking interface changes.
- Add methods carefully to public interfaces.
- Use default methods only when semantically appropriate.
- Avoid deep interface inheritance hierarchies.
- Use sealed interfaces for intentionally closed type families.
- Use marker interfaces only when type-level marking is genuinely useful.
- Prefer annotations when metadata rather than type identity is required.
- Avoid unnecessary downcasting.
- Avoid repeated instanceof checks.
- Let polymorphism select behavior.
- Keep implementations independent.
- Test implementations against the same contract.
- Choose abstract classes when shared state is central.
- Choose interfaces when contracts and multiple implementations are central.
- Combine interfaces with composition.
- Avoid premature abstraction.
- Create interfaces around meaningful boundaries.
- Keep calling code independent of implementation details.
- Use interfaces to make systems easier to extend, test, and maintain.
Common Misconceptions
- Interfaces are not classes.
- Interfaces cannot be instantiated directly.
- Interfaces can be used as reference types.
- A class can implement multiple interfaces.
- An interface can extend multiple interfaces.
- A class cannot extend multiple classes.
- Interface abstract methods are public.
- Implementing methods must be public.
- Interface fields are public, static, and final.
- Interface fields are constants.
- Interfaces do not have normal instance constructors.
- Modern interfaces can contain method implementations.
- Default methods have implementations.
- Static interface methods have implementations.
- Private interface methods can have implementations.
- Default methods can be overridden.
- Static interface methods are not runtime polymorphic.
- A superclass method takes priority over an interface default method.
- Conflicting default methods must be resolved.
- Interfaces support abstraction.
- Interfaces support runtime polymorphism.
- Interfaces support loose coupling.
- Interfaces are not only useful when multiple implementations already exist.
- Functional interfaces contain one abstract method.
- Functional interfaces may still contain default and static methods.
- Lambda expressions work with functional interfaces.
- Interfaces and abstract classes serve different design purposes.
- Interfaces do not automatically guarantee loose coupling.
- Poorly designed interfaces can still create tight coupling.
- More interfaces do not automatically create better architecture.
Practice Exercises
- Create a Payment interface.
- Add a pay() method.
- Create CardPayment and UPIPayment.
- Process both through Payment references.
- Add a default receipt method.
- Create Printable and Scannable interfaces.
- Create a MultiFunctionPrinter class.
- Implement both interfaces.
- Call methods through separate interface references.
- Create two interfaces with the same default method.
- Implement both in one class.
- Observe the compilation error.
- Override the conflicting method.
- Call specific parent defaults using InterfaceName.super.
- Create a NotificationService interface.
- Create Email, SMS, and Push implementations.
- Inject the interface into a NotificationManager.
- Switch implementations without changing the manager.
- Create a Calculator functional interface.
- Add one calculate() method.
- Implement addition using a lambda.
- Implement multiplication using a lambda.
- Test both operations.
- Create a ProductRepository interface.
- Add save(), findById(), and delete() methods.
- Create an in-memory implementation.
- Create a service depending on the interface.
- Inject the implementation.
- Create one large Worker interface.
- Identify methods not required by every implementation.
- Split it into focused interfaces.
- Implement only required capabilities.
- Create a Storage interface.
- Create LocalStorage and CloudStorage.
- Inject Storage into a FileService.
- Switch storage implementations.
- Create a test storage implementation.
Common Interview Questions
What is an interface in Java?
An interface is a reference type that defines a contract for implementing classes.
Can we create an object of an interface?
No. An interface cannot be instantiated directly.
Can an interface be used as a reference type?
Yes. It can refer to objects of implementing classes.
Can a class implement multiple interfaces?
Yes.
Can an interface extend multiple interfaces?
Yes.
What are interface fields implicitly?
They are implicitly public, static, and final.
What are abstract interface methods implicitly?
They are implicitly public and abstract.
What is a default method?
A default method is an interface method with an implementation declared using the default keyword.
Can a class override a default method?
Yes.
What happens when two interfaces provide the same default method?
The implementing class must explicitly resolve the conflict by overriding the method.
Can interfaces have static methods?
Yes.
Can interfaces have private methods?
Yes. Private methods can support shared internal interface logic.
What is a functional interface?
A functional interface contains exactly one abstract method.
Why are functional interfaces important?
They can be implemented using lambda expressions and method references.
What is the difference between an interface and an abstract class?
An interface primarily defines a contract and supports multiple implementation types, while an abstract class can provide shared instance state, constructors, and common implementation.
Frequently Asked Questions
Should every class have an interface?
No. Create an interface when a meaningful contract, replaceable implementation, polymorphic boundary, or multiple implementation model is useful.
Can an interface have a constructor?
No. Interfaces do not have normal instance constructors.
Can an interface have fields?
Yes, but all interface fields are constants because they are implicitly public, static, and final.
Can a functional interface have default methods?
Yes. It must have exactly one abstract method, but it may contain default and static methods.
Can one class extend a class and implement interfaces?
Yes. A class can extend one class and implement multiple interfaces.
Are interfaces only for multiple inheritance?
No. They are primarily used for contracts, abstraction, polymorphism, loose coupling, dependency injection, and replaceable implementations.
What should I learn after Interfaces?
The next lesson covers Exception Handling in Java.
Key Takeaways
- An interface defines a contract.
- Interfaces are reference types.
- Interfaces support abstraction.
- Interfaces support polymorphism.
- Interfaces support loose coupling.
- An interface cannot be instantiated directly.
- An interface can be used as a reference type.
- A class implements an interface using implements.
- A class can implement multiple interfaces.
- An interface can extend another interface.
- An interface can extend multiple interfaces.
- Abstract interface methods are implicitly public and abstract.
- Implementing methods must be public.
- Interface fields are implicitly public, static, and final.
- Interface fields are constants.
- Interfaces do not have normal instance constructors.
- Modern interfaces can contain default methods.
- Default methods contain implementations.
- Default methods can be overridden.
- Conflicting default methods must be resolved.
- A superclass method takes priority over an interface default method.
- Interfaces can contain static methods.
- Static interface methods belong to the interface.
- Static interface methods are called using the interface name.
- Interfaces can contain private methods.
- Private methods support internal shared logic.
- Interfaces can contain private static methods.
- Marker interfaces identify special type characteristics.
- Functional interfaces contain exactly one abstract method.
- @FunctionalInterface documents and validates functional interfaces.
- Functional interfaces support lambda expressions.
- Functional interfaces support method references.
- Predicate represents a condition.
- Function transforms one value into another.
- Consumer accepts a value without returning a result.
- Supplier provides a value without input.
- Interfaces can be used as method parameters.
- Interfaces can be used as return types.
- Interface arrays can contain different implementations.
- Interface collections can contain different implementations.
- Interfaces are central to dependency injection.
- Dependency injection provides implementations from outside.
- Interfaces reduce dependency on concrete classes.
- Loose coupling improves flexibility.
- Interface segregation favors small focused contracts.
- Composition works well with interfaces.
- Nested interfaces can organize related contracts.
- Sealed interfaces restrict permitted implementations.
- Interfaces differ from abstract classes.
- Interfaces are ideal for capabilities and contracts.
- Abstract classes are useful for shared state and implementation.
- Not every class needs an interface.
- Interfaces should represent meaningful boundaries.
- Good interfaces are small and cohesive.
- Good interfaces hide implementation details.
- Good interfaces remain stable.
- Interfaces make systems easier to extend.
- Interfaces improve testability.
- Interfaces are widely used in Java frameworks and enterprise applications.
Summary
An interface is a Java reference type that defines a contract. It specifies behavior that implementing classes agree to provide while allowing each implementation to use its own internal logic.
A class implements an interface using the implements keyword. A concrete class must provide implementations for all required abstract methods, and those methods must remain public.
Interfaces support runtime polymorphism because one interface reference can represent objects of many implementation classes. This allows calling code to depend on general contracts instead of specific implementations.
A class can implement multiple interfaces, and an interface can extend multiple interfaces. This allows Java programs to model multiple capabilities without allowing multiple class inheritance.
Modern interfaces can contain abstract methods, default methods, static methods, private methods, and private static methods. Default methods support shared behavior and interface evolution, while private methods support internal code reuse.
Functional interfaces contain exactly one abstract method and can be implemented using lambda expressions and method references. Java provides common functional interfaces such as Predicate, Function, Consumer, and Supplier.
Interfaces are central to dependency injection and loose coupling. A class can depend on an interface while the actual implementation is supplied from outside, making the system easier to extend and test.
Good interface design uses small focused contracts, stable method definitions, meaningful abstraction boundaries, minimal implementation leakage, and composition instead of unnecessary concrete dependencies.
- You understand what an interface is.
- You understand why interfaces are useful.
- You can declare interfaces.
- You can implement interfaces.
- You understand interface methods.
- You understand interface fields.
- You know interface rules.
- You know implementation rules.
- You understand why interfaces cannot be instantiated.
- You can use interface references.
- You understand interface polymorphism.
- You can create multiple implementations.
- You can implement multiple interfaces.
- You understand multiple inheritance with interfaces.
- You can extend interfaces.
- You understand multiple interface inheritance.
- You can create default methods.
- You can override default methods.
- You can resolve default method conflicts.
- You understand class method priority.
- You can create static interface methods.
- You understand private interface methods.
- You understand private static methods.
- You know all major interface method types.
- You understand interface constants.
- You understand marker interfaces.
- You understand functional interfaces.
- You can use @FunctionalInterface.
- You understand lambda expressions.
- You understand method references.
- You know the main built-in functional interfaces.
- You understand Predicate.
- You understand Function.
- You understand Consumer.
- You understand Supplier.
- You can use interfaces as method parameters.
- You can use interfaces as return types.
- You can create interface arrays.
- You can create interface collections.
- You understand dependency injection.
- You understand loose coupling.
- You understand interface segregation.
- You understand composition with interfaces.
- You understand nested interfaces.
- You understand sealed interfaces.
- You know the difference between interfaces and abstract classes.
- You know when to use interfaces.
- You know when to avoid unnecessary interfaces.
- You can design practical interface-based systems.
- You can identify common interface errors.
- You know interface best practices.
- You are ready to learn Exception Handling in Java.