64% complete
Interfaces in Java
Interfaces are a fundamental concept in Java that allow you to define a contract for classes to implement. They are a key mechanism for achieving abstraction and enabling a form of multiple inheritance in Java.
What is an Interface?
An interface in Java is a reference type, similar to a class, that can contain only constants, method signatures, default methods, static methods, and nested types. Method bodies exist only for default and static methods. Interfaces cannot be instantiated—they can only be implemented by classes or extended by other interfaces.
Think of an interface as a contract that a class agrees to fulfill. When a class implements an interface, it promises to provide implementations for all the methods declared in the interface.
Interface vs Abstract Class
Interface
- Can't have constructor
- All methods implicitly public
- Can't have instance fields
- A class can implement multiple interfaces
- Supports default methods (Java 8+)
- 100% abstraction
Abstract Class
- Can have constructor
- Can have any access modifier
- Can have instance fields
- A class can extend only one abstract class
- Can have concrete methods
- Partial abstraction
Defining an Interface
Here's the basic syntax for defining an interface in Java:
1public interface InterfaceName {2 // Constants (implicitly public, static, and final)3 int MAX_SIZE = 100;45 // Method signatures (implicitly public and abstract)6 void methodOne();7 String methodTwo(int parameter);89 // Default method (Java 8+)10 default void defaultMethod() {11 System.out.println("Default implementation");12 }1314 // Static method (Java 8+)15 static void staticMethod() {16 System.out.println("Static method in interface");17 }18}
Key points about interfaces:
- Interface methods are implicitly
public
andabstract
(no need to use these keywords) - Interface variables are implicitly
public
,static
, andfinal
(constants) - Since Java 8, interfaces can have default and static methods with implementations
- Since Java 9, interfaces can also have private methods to help with code organization
Implementing an Interface
A class implements an interface using the implements
keyword. When a class implements an interface, it must provide implementations for all the abstract methods declared in the interface.
1// Define an interface2interface Animal {3 void makeSound();4 void eat();5}67// Class implementing the interface8public class Dog implements Animal {9 // Must implement all methods from the Animal interface10 @Override11 public void makeSound() {12 System.out.println("Dog barks: Woof woof!");13 }1415 @Override16 public void eat() {17 System.out.println("Dog eats meat");18 }1920 // Class can have its own methods as well21 public void wagTail() {22 System.out.println("Dog wags tail");23 }24}2526// Usage27public class InterfaceExample {28 public static void main(String[] args) {29 Dog dog = new Dog();30 dog.makeSound();31 dog.eat();32 dog.wagTail();3334 // We can also use interface as a reference type35 Animal animal = new Dog();36 animal.makeSound();37 animal.eat();38 // animal.wagTail(); // Error: Animal interface doesn't have wagTail method39 }40}4142/* Output:43Dog barks: Woof woof!44Dog eats meat45Dog wags tail46Dog barks: Woof woof!47Dog eats meat48*/
Multiple Interfaces
One of the key advantages of interfaces is that a class can implement multiple interfaces, which is Java's way of supporting multiple inheritance of type. This allows a class to inherit method signatures from multiple sources.
1interface Swimmer {2 void swim();3}45interface Flyer {6 void fly();7}89// Class implementing multiple interfaces10class Duck implements Swimmer, Flyer {11 @Override12 public void swim() {13 System.out.println("Duck swims in the pond");14 }1516 @Override17 public void fly() {18 System.out.println("Duck flies in the sky");19 }2021 public void quack() {22 System.out.println("Duck quacks");23 }24}2526public class MultipleInterfacesExample {27 public static void main(String[] args) {28 Duck duck = new Duck();29 duck.swim();30 duck.fly();31 duck.quack();3233 // Using interface references34 Swimmer swimmer = duck;35 swimmer.swim();3637 Flyer flyer = duck;38 flyer.fly();39 }40}4142/* Output:43Duck swims in the pond44Duck flies in the sky45Duck quacks46Duck swims in the pond47Duck flies in the sky48*/
Default Methods in Interfaces
Since Java 8, interfaces can include default methods with implementations. This feature was introduced to enable interfaces to evolve over time without breaking existing implementations.
1interface Vehicle {2 void start();3 void stop();45 // Default method with implementation6 default void honk() {7 System.out.println("Beep beep!");8 }9}1011class Car implements Vehicle {12 @Override13 public void start() {14 System.out.println("Car starting engine");15 }1617 @Override18 public void stop() {19 System.out.println("Car stopping engine");20 }2122 // No need to implement honk() as it has a default implementation23}2425class Motorcycle implements Vehicle {26 @Override27 public void start() {28 System.out.println("Motorcycle starting engine");29 }3031 @Override32 public void stop() {33 System.out.println("Motorcycle stopping engine");34 }3536 // Override the default method37 @Override38 public void honk() {39 System.out.println("Motorcycle horn: Beep!");40 }41}4243public class DefaultMethodExample {44 public static void main(String[] args) {45 Car car = new Car();46 car.start();47 car.honk(); // Uses default implementation48 car.stop();4950 System.out.println();5152 Motorcycle motorcycle = new Motorcycle();53 motorcycle.start();54 motorcycle.honk(); // Uses overridden implementation55 motorcycle.stop();56 }57}5859/* Output:60Car starting engine61Beep beep!62Car stopping engine6364Motorcycle starting engine65Motorcycle horn: Beep!66Motorcycle stopping engine67*/
Default Method Conflict
If a class implements two interfaces that contain default methods with the same signature, the implementing class must override the method to resolve the conflict. Otherwise, a compilation error will occur.
Static Methods in Interfaces
Java 8 also introduced static methods in interfaces. These methods belong to the interface itself, not to the implementing classes, and can be called directly on the interface.
1interface MathOperations {2 // Static method in interface3 static int add(int a, int b) {4 return a + b;5 }67 static int subtract(int a, int b) {8 return a - b;9 }1011 // Abstract method12 int multiply(int a, int b);13}1415class Calculator implements MathOperations {16 // Must implement abstract method17 @Override18 public int multiply(int a, int b) {19 return a * b;20 }2122 // Can add its own methods23 public int divide(int a, int b) {24 if (b == 0) {25 throw new ArithmeticException("Cannot divide by zero");26 }27 return a / b;28 }29}3031public class StaticMethodExample {32 public static void main(String[] args) {33 // Call static methods directly on the interface34 System.out.println("10 + 5 = " + MathOperations.add(10, 5));35 System.out.println("10 - 5 = " + MathOperations.subtract(10, 5));3637 // Instance method requires an object38 Calculator calc = new Calculator();39 System.out.println("10 * 5 = " + calc.multiply(10, 5));40 System.out.println("10 / 5 = " + calc.divide(10, 5));41 }42}4344/* Output:4510 + 5 = 154610 - 5 = 54710 * 5 = 504810 / 5 = 249*/
Private Methods in Interfaces
Since Java 9, interfaces can include private methods. These methods can be used to share code between default methods without making the methods part of the public API.
1interface Logger {2 // Default methods3 default void logInfo(String message) {4 log("INFO", message);5 }67 default void logWarning(String message) {8 log("WARNING", message);9 }1011 default void logError(String message) {12 log("ERROR", message);13 }1415 // Private helper method (Java 9+)16 private void log(String level, String message) {17 System.out.println(level + ": " + message);18 }19}2021class FileLogger implements Logger {22 // No need to implement any methods as all have default implementations23}2425public class PrivateMethodExample {26 public static void main(String[] args) {27 FileLogger logger = new FileLogger();28 logger.logInfo("Application started");29 logger.logWarning("Low memory");30 logger.logError("Connection failed");31 }32}3334/* Output:35INFO: Application started36WARNING: Low memory37ERROR: Connection failed38*/
Functional Interfaces
A functional interface is an interface that contains exactly one abstract method. These interfaces are used as the basis for lambda expressions in Java. The @FunctionalInterface
annotation can be used to ensure that the interface cannot have more than one abstract method.
1// Functional interface with exactly one abstract method2@FunctionalInterface3interface Greeting {4 void greet(String name);56 // Default methods don't count toward the single abstract method rule7 default void greetDefault() {8 System.out.println("Hello, World!");9 }10}1112public class FunctionalInterfaceExample {13 public static void main(String[] args) {14 // Traditional way using anonymous class15 Greeting traditionalGreeting = new Greeting() {16 @Override17 public void greet(String name) {18 System.out.println("Hello, " + name + "!");19 }20 };2122 // Using lambda expression (more concise)23 Greeting lambdaGreeting = (name) -> System.out.println("Hello, " + name + "!");2425 // Using both implementations26 traditionalGreeting.greet("Alice");27 lambdaGreeting.greet("Bob");2829 // Both can use the default method30 traditionalGreeting.greetDefault();31 lambdaGreeting.greetDefault();32 }33}3435/* Output:36Hello, Alice!37Hello, Bob!38Hello, World!39Hello, World!40*/
Java provides several built-in functional interfaces in the java.util.function
package:
Functional Interface | Method | Description |
---|---|---|
Predicate<T> | boolean test(T t) | Represents a predicate (boolean-valued function) of one argument |
Consumer<T> | void accept(T t) | Represents an operation that accepts a single input argument and returns no result |
Function<T, R> | R apply(T t) | Represents a function that accepts one argument and produces a result |
Supplier<T> | T get() | Represents a supplier of results |
1import java.util.function.Predicate;2import java.util.function.Consumer;3import java.util.function.Function;4import java.util.function.Supplier;5import java.util.ArrayList;6import java.util.List;78public class BuiltinFunctionalInterfacesExample {9 public static void main(String[] args) {10 // Predicate - tests a condition11 Predicate<Integer> isEven = n -> n % 2 == 0;12 System.out.println("Is 4 even? " + isEven.test(4));13 System.out.println("Is 7 even? " + isEven.test(7));1415 // Consumer - accepts a value and performs an operation16 Consumer<String> printUpperCase = s -> System.out.println(s.toUpperCase());17 printUpperCase.accept("hello world");1819 // Function - transforms a value20 Function<String, Integer> stringLength = s -> s.length();21 System.out.println("Length of 'Java': " + stringLength.apply("Java"));2223 // Supplier - provides a value24 Supplier<Double> randomValue = () -> Math.random();25 System.out.println("Random value: " + randomValue.get());2627 // Practical example: filtering a list28 List<Integer> numbers = new ArrayList<>();29 numbers.add(1);30 numbers.add(2);31 numbers.add(3);32 numbers.add(4);33 numbers.add(5);3435 System.out.println("Even numbers:");36 numbers.stream()37 .filter(isEven)38 .forEach(System.out::println);39 }40}4142/* Output:43Is 4 even? true44Is 7 even? false45HELLO WORLD46Length of 'Java': 447Random value: 0.753131945844961948Even numbers:49250451*/
Interface Inheritance
Interfaces can extend other interfaces using the extends
keyword. An interface that extends another interface inherits all its methods and constants.
1// Base interface2interface Movable {3 void move();4}56// Interface extending another interface7interface Vehicle extends Movable {8 void start();9 void stop();10}1112// Class implementing the extended interface13class Car implements Vehicle {14 @Override15 public void move() {16 System.out.println("Car is moving");17 }1819 @Override20 public void start() {21 System.out.println("Car engine started");22 }2324 @Override25 public void stop() {26 System.out.println("Car engine stopped");27 }28}2930public class InterfaceInheritanceExample {31 public static void main(String[] args) {32 Car car = new Car();33 car.start();34 car.move();35 car.stop();3637 // Using interface references38 Vehicle vehicle = car;39 vehicle.start();40 vehicle.move();41 vehicle.stop();4243 Movable movable = car;44 movable.move(); // Can only call methods from Movable interface45 }46}4748/* Output:49Car engine started50Car is moving51Car engine stopped52Car engine started53Car is moving54Car engine stopped55Car is moving56*/
An interface can extend multiple interfaces, which is not possible with classes:
1interface Swimmer {2 void swim();3}45interface Flyer {6 void fly();7}89// Interface extending multiple interfaces10interface FlyingFish extends Swimmer, Flyer {11 void glide();12}1314// Class implementing the combined interface15class AquaticBird implements FlyingFish {16 @Override17 public void swim() {18 System.out.println("Bird swims in water");19 }2021 @Override22 public void fly() {23 System.out.println("Bird flies in air");24 }2526 @Override27 public void glide() {28 System.out.println("Bird glides above water");29 }30}3132public class MultipleInheritanceExample {33 public static void main(String[] args) {34 AquaticBird bird = new AquaticBird();35 bird.swim();36 bird.fly();37 bird.glide();38 }39}4041/* Output:42Bird swims in water43Bird flies in air44Bird glides above water45*/
Marker Interfaces
A marker interface is an interface that has no methods or constants. It provides runtime type information about objects, so the compiler and JVM can take special action when needed.
1// Marker interface (no methods)2interface Serializable {3 // No methods or constants4}56// Another marker interface7interface Cloneable {8 // No methods or constants9}1011// Class implementing marker interfaces12class User implements Serializable, Cloneable {13 private String name;14 private int age;1516 public User(String name, int age) {17 this.name = name;18 this.age = age;19 }2021 @Override22 public String toString() {23 return "User{name='" + name + "', age=" + age + "}";24 }25}2627public class MarkerInterfaceExample {28 public static void main(String[] args) {29 User user = new User("John", 30);3031 // Check if object implements marker interfaces32 if (user instanceof Serializable) {33 System.out.println("User is serializable");34 }3536 if (user instanceof Cloneable) {37 System.out.println("User is cloneable");38 }39 }40}4142/* Output:43User is serializable44User is cloneable45*/
Common Marker Interfaces in Java
java.io.Serializable
- Allows objects to be converted to a byte streamjava.lang.Cloneable
- Indicates that an object can be clonedjava.util.RandomAccess
- Indicates that a list supports fast random access
Best Practices for Using Interfaces
Design for API
Use interfaces to define public APIs. This allows you to change the implementation without affecting clients.
Interface Segregation
Keep interfaces focused and cohesive. It's better to have many small, specific interfaces than one large, general-purpose interface.
Program to Interfaces
Use interface types as variables, parameters, and return types rather than concrete classes to make code more flexible.
Use Default Methods Sparingly
Default methods are useful for evolving interfaces, but overusing them can lead to the same problems as multiple inheritance.
Practice Exercises
- Create a
Playable
interface and implement it in multiple game character classes. - Design a system with multiple interfaces to represent different capabilities (e.g.,
Printable
,Saveable
,Exportable
). - Implement a functional interface and use it with both anonymous classes and lambda expressions.
- Create an interface hierarchy for a payment processing system.
- Use default methods to add new functionality to an existing interface without breaking implementations.
Summary
In this tutorial, you've learned:
- What interfaces are and how they differ from abstract classes
- How to define and implement interfaces in Java
- How to implement multiple interfaces to achieve a form of multiple inheritance
- How to use default, static, and private methods in interfaces
- What functional interfaces are and how they relate to lambda expressions
- How interfaces can inherit from other interfaces
- The concept of marker interfaces and their use cases
- Best practices for designing and using interfaces
Interfaces are a powerful feature in Java that enable abstraction, polymorphism, and a form of multiple inheritance. They are essential for designing flexible and maintainable code, especially in large applications. By programming to interfaces rather than implementations, you can create code that is more adaptable to change.
Related Tutorials
Learn about class inheritance and method overriding.
Learn moreUnderstand abstract classes and their use cases.
Learn moreMaster the principles of OOP in Java.
Learn more