Progress9 of 14 topics

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:

java
1public interface InterfaceName {
2 // Constants (implicitly public, static, and final)
3 int MAX_SIZE = 100;
4
5 // Method signatures (implicitly public and abstract)
6 void methodOne();
7 String methodTwo(int parameter);
8
9 // Default method (Java 8+)
10 default void defaultMethod() {
11 System.out.println("Default implementation");
12 }
13
14 // 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 and abstract (no need to use these keywords)
  • Interface variables are implicitly public, static, and final (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.

java
1// Define an interface
2interface Animal {
3 void makeSound();
4 void eat();
5}
6
7// Class implementing the interface
8public class Dog implements Animal {
9 // Must implement all methods from the Animal interface
10 @Override
11 public void makeSound() {
12 System.out.println("Dog barks: Woof woof!");
13 }
14
15 @Override
16 public void eat() {
17 System.out.println("Dog eats meat");
18 }
19
20 // Class can have its own methods as well
21 public void wagTail() {
22 System.out.println("Dog wags tail");
23 }
24}
25
26// Usage
27public class InterfaceExample {
28 public static void main(String[] args) {
29 Dog dog = new Dog();
30 dog.makeSound();
31 dog.eat();
32 dog.wagTail();
33
34 // We can also use interface as a reference type
35 Animal animal = new Dog();
36 animal.makeSound();
37 animal.eat();
38 // animal.wagTail(); // Error: Animal interface doesn't have wagTail method
39 }
40}
41
42/* Output:
43Dog barks: Woof woof!
44Dog eats meat
45Dog wags tail
46Dog barks: Woof woof!
47Dog eats meat
48*/

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.

java
1interface Swimmer {
2 void swim();
3}
4
5interface Flyer {
6 void fly();
7}
8
9// Class implementing multiple interfaces
10class Duck implements Swimmer, Flyer {
11 @Override
12 public void swim() {
13 System.out.println("Duck swims in the pond");
14 }
15
16 @Override
17 public void fly() {
18 System.out.println("Duck flies in the sky");
19 }
20
21 public void quack() {
22 System.out.println("Duck quacks");
23 }
24}
25
26public class MultipleInterfacesExample {
27 public static void main(String[] args) {
28 Duck duck = new Duck();
29 duck.swim();
30 duck.fly();
31 duck.quack();
32
33 // Using interface references
34 Swimmer swimmer = duck;
35 swimmer.swim();
36
37 Flyer flyer = duck;
38 flyer.fly();
39 }
40}
41
42/* Output:
43Duck swims in the pond
44Duck flies in the sky
45Duck quacks
46Duck swims in the pond
47Duck flies in the sky
48*/

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.

java
1interface Vehicle {
2 void start();
3 void stop();
4
5 // Default method with implementation
6 default void honk() {
7 System.out.println("Beep beep!");
8 }
9}
10
11class Car implements Vehicle {
12 @Override
13 public void start() {
14 System.out.println("Car starting engine");
15 }
16
17 @Override
18 public void stop() {
19 System.out.println("Car stopping engine");
20 }
21
22 // No need to implement honk() as it has a default implementation
23}
24
25class Motorcycle implements Vehicle {
26 @Override
27 public void start() {
28 System.out.println("Motorcycle starting engine");
29 }
30
31 @Override
32 public void stop() {
33 System.out.println("Motorcycle stopping engine");
34 }
35
36 // Override the default method
37 @Override
38 public void honk() {
39 System.out.println("Motorcycle horn: Beep!");
40 }
41}
42
43public class DefaultMethodExample {
44 public static void main(String[] args) {
45 Car car = new Car();
46 car.start();
47 car.honk(); // Uses default implementation
48 car.stop();
49
50 System.out.println();
51
52 Motorcycle motorcycle = new Motorcycle();
53 motorcycle.start();
54 motorcycle.honk(); // Uses overridden implementation
55 motorcycle.stop();
56 }
57}
58
59/* Output:
60Car starting engine
61Beep beep!
62Car stopping engine
63
64Motorcycle starting engine
65Motorcycle horn: Beep!
66Motorcycle stopping engine
67*/

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.

java
1interface MathOperations {
2 // Static method in interface
3 static int add(int a, int b) {
4 return a + b;
5 }
6
7 static int subtract(int a, int b) {
8 return a - b;
9 }
10
11 // Abstract method
12 int multiply(int a, int b);
13}
14
15class Calculator implements MathOperations {
16 // Must implement abstract method
17 @Override
18 public int multiply(int a, int b) {
19 return a * b;
20 }
21
22 // Can add its own methods
23 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}
30
31public class StaticMethodExample {
32 public static void main(String[] args) {
33 // Call static methods directly on the interface
34 System.out.println("10 + 5 = " + MathOperations.add(10, 5));
35 System.out.println("10 - 5 = " + MathOperations.subtract(10, 5));
36
37 // Instance method requires an object
38 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}
43
44/* Output:
4510 + 5 = 15
4610 - 5 = 5
4710 * 5 = 50
4810 / 5 = 2
49*/

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.

java
1interface Logger {
2 // Default methods
3 default void logInfo(String message) {
4 log("INFO", message);
5 }
6
7 default void logWarning(String message) {
8 log("WARNING", message);
9 }
10
11 default void logError(String message) {
12 log("ERROR", message);
13 }
14
15 // Private helper method (Java 9+)
16 private void log(String level, String message) {
17 System.out.println(level + ": " + message);
18 }
19}
20
21class FileLogger implements Logger {
22 // No need to implement any methods as all have default implementations
23}
24
25public 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}
33
34/* Output:
35INFO: Application started
36WARNING: Low memory
37ERROR: Connection failed
38*/

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.

java
1// Functional interface with exactly one abstract method
2@FunctionalInterface
3interface Greeting {
4 void greet(String name);
5
6 // Default methods don't count toward the single abstract method rule
7 default void greetDefault() {
8 System.out.println("Hello, World!");
9 }
10}
11
12public class FunctionalInterfaceExample {
13 public static void main(String[] args) {
14 // Traditional way using anonymous class
15 Greeting traditionalGreeting = new Greeting() {
16 @Override
17 public void greet(String name) {
18 System.out.println("Hello, " + name + "!");
19 }
20 };
21
22 // Using lambda expression (more concise)
23 Greeting lambdaGreeting = (name) -> System.out.println("Hello, " + name + "!");
24
25 // Using both implementations
26 traditionalGreeting.greet("Alice");
27 lambdaGreeting.greet("Bob");
28
29 // Both can use the default method
30 traditionalGreeting.greetDefault();
31 lambdaGreeting.greetDefault();
32 }
33}
34
35/* Output:
36Hello, Alice!
37Hello, Bob!
38Hello, World!
39Hello, World!
40*/

Java provides several built-in functional interfaces in the java.util.function package:

Functional InterfaceMethodDescription
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
java
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;
7
8public class BuiltinFunctionalInterfacesExample {
9 public static void main(String[] args) {
10 // Predicate - tests a condition
11 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));
14
15 // Consumer - accepts a value and performs an operation
16 Consumer<String> printUpperCase = s -> System.out.println(s.toUpperCase());
17 printUpperCase.accept("hello world");
18
19 // Function - transforms a value
20 Function<String, Integer> stringLength = s -> s.length();
21 System.out.println("Length of 'Java': " + stringLength.apply("Java"));
22
23 // Supplier - provides a value
24 Supplier<Double> randomValue = () -> Math.random();
25 System.out.println("Random value: " + randomValue.get());
26
27 // Practical example: filtering a list
28 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);
34
35 System.out.println("Even numbers:");
36 numbers.stream()
37 .filter(isEven)
38 .forEach(System.out::println);
39 }
40}
41
42/* Output:
43Is 4 even? true
44Is 7 even? false
45HELLO WORLD
46Length of 'Java': 4
47Random value: 0.7531319458449619
48Even numbers:
492
504
51*/

Interface Inheritance

Interfaces can extend other interfaces using the extends keyword. An interface that extends another interface inherits all its methods and constants.

java
1// Base interface
2interface Movable {
3 void move();
4}
5
6// Interface extending another interface
7interface Vehicle extends Movable {
8 void start();
9 void stop();
10}
11
12// Class implementing the extended interface
13class Car implements Vehicle {
14 @Override
15 public void move() {
16 System.out.println("Car is moving");
17 }
18
19 @Override
20 public void start() {
21 System.out.println("Car engine started");
22 }
23
24 @Override
25 public void stop() {
26 System.out.println("Car engine stopped");
27 }
28}
29
30public class InterfaceInheritanceExample {
31 public static void main(String[] args) {
32 Car car = new Car();
33 car.start();
34 car.move();
35 car.stop();
36
37 // Using interface references
38 Vehicle vehicle = car;
39 vehicle.start();
40 vehicle.move();
41 vehicle.stop();
42
43 Movable movable = car;
44 movable.move(); // Can only call methods from Movable interface
45 }
46}
47
48/* Output:
49Car engine started
50Car is moving
51Car engine stopped
52Car engine started
53Car is moving
54Car engine stopped
55Car is moving
56*/

An interface can extend multiple interfaces, which is not possible with classes:

java
1interface Swimmer {
2 void swim();
3}
4
5interface Flyer {
6 void fly();
7}
8
9// Interface extending multiple interfaces
10interface FlyingFish extends Swimmer, Flyer {
11 void glide();
12}
13
14// Class implementing the combined interface
15class AquaticBird implements FlyingFish {
16 @Override
17 public void swim() {
18 System.out.println("Bird swims in water");
19 }
20
21 @Override
22 public void fly() {
23 System.out.println("Bird flies in air");
24 }
25
26 @Override
27 public void glide() {
28 System.out.println("Bird glides above water");
29 }
30}
31
32public 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}
40
41/* Output:
42Bird swims in water
43Bird flies in air
44Bird glides above water
45*/

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.

java
1// Marker interface (no methods)
2interface Serializable {
3 // No methods or constants
4}
5
6// Another marker interface
7interface Cloneable {
8 // No methods or constants
9}
10
11// Class implementing marker interfaces
12class User implements Serializable, Cloneable {
13 private String name;
14 private int age;
15
16 public User(String name, int age) {
17 this.name = name;
18 this.age = age;
19 }
20
21 @Override
22 public String toString() {
23 return "User{name='" + name + "', age=" + age + "}";
24 }
25}
26
27public class MarkerInterfaceExample {
28 public static void main(String[] args) {
29 User user = new User("John", 30);
30
31 // Check if object implements marker interfaces
32 if (user instanceof Serializable) {
33 System.out.println("User is serializable");
34 }
35
36 if (user instanceof Cloneable) {
37 System.out.println("User is cloneable");
38 }
39 }
40}
41
42/* Output:
43User is serializable
44User is cloneable
45*/

Common Marker Interfaces in Java

  • java.io.Serializable - Allows objects to be converted to a byte stream
  • java.lang.Cloneable - Indicates that an object can be cloned
  • java.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

  1. Create a Playable interface and implement it in multiple game character classes.
  2. Design a system with multiple interfaces to represent different capabilities (e.g., Printable, Saveable, Exportable).
  3. Implement a functional interface and use it with both anonymous classes and lambda expressions.
  4. Create an interface hierarchy for a payment processing system.
  5. 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 more

Understand abstract classes and their use cases.

Learn more

Master the principles of OOP in Java.

Learn more