1. Introduction
In Java you cannot inherit from multiple classes at once. This is by design to avoid the diamond problem — a situation where two parent classes define the same method and it’s unclear which implementation to use. But you can implement as many interfaces as you like! Why? Because an interface is only a contract; it contains no implementation (before Java 8 — no implementation; since Java 8 — default and static methods are possible). That means there’s no confusion with inheriting code.
This is similar to real life: you can be a “Driver”, a “Computer user”, and a “Swimmer” at the same time. Each of these “interfaces” describes certain skills but doesn’t force you to be a copy of someone else.
Syntax for implementing multiple interfaces
In Java, a class can implement multiple interfaces by listing them separated by commas after the implements keyword. Here is a basic example:
public interface Movable {
void move(int x, int y);
}
public interface Chargeable {
void charge();
}
public class Robot implements Movable, Chargeable {
@Override
public void move(int x, int y) {
System.out.println("Robot moves to (" + x + ", " + y + ")");
}
@Override
public void charge() {
System.out.println("Robot is charging.");
}
}
In this example, Robot is a versatile fellow: it both moves and charges. Just like in life — the more skills you have, the more often you get invited to interviews!
2. Why do this? Practical examples
Example 1. Different “roles” of an object
Imagine you are designing a game character:
- It can move (Movable)
- It can attack (Attackable)
- It can be saved to a file (Serializable — such an interface exists in the Java standard library)
public interface Attackable {
void attack();
}
public class Hero implements Movable, Attackable, java.io.Serializable {
@Override
public void move(int x, int y) {
System.out.println("The hero moves to a new position.");
}
@Override
public void attack() {
System.out.println("The hero strikes!");
}
}
Now your class can be used in many different contexts: it can be passed to methods that require any of these interfaces.
Example 2. Combining standard interfaces
Very often the Java standard library includes interfaces like Comparable (for comparing objects) and Serializable (for saving objects to a file or sending them over the network). Sometimes you need an object to be both:
public class Person implements Comparable<Person>, java.io.Serializable {
private String name;
private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
@Override
public int compareTo(Person other) {
return Integer.compare(this.age, other.age);
}
}
Now Person objects can be sorted (for example, in a list) and written to a file.
3. Features and limitations
One implementation per method
If two interfaces define a method with the same signature, you only need to implement it once. Example:
public interface A {
void doSomething();
}
public interface B {
void doSomething();
}
public class MyClass implements A, B {
@Override
public void doSomething() {
System.out.println("doSomething implementation for both interfaces.");
}
}
Java won’t complain — the key is that the signatures match. If the methods differ by signature, they are considered different methods — you must implement each one.
No diamond problem
Unlike multiple inheritance of classes, when implementing several interfaces you don’t end up inheriting two different implementations of the same method. Before Java 8, interfaces had no implementation at all, and with the advent of default methods — if there’s a conflict, you must resolve it explicitly (more on this in the next lecture).
No state
Interfaces cannot contain regular fields (only constants — public static final). Therefore, there’s no confusion with “two parent fields of the same name”.
4. Example: implementing several interfaces in one class
Let’s add new capabilities to our training app (say, a zoo). Suppose we have animals that can move and make sounds:
public interface Movable {
void move(int x, int y);
}
public interface Soundable {
void makeSound();
}
public class Dog implements Movable, Soundable {
private String name;
public Dog(String name) {
this.name = name;
}
@Override
public void move(int x, int y) {
System.out.println(name + " runs to (" + x + ", " + y + ")");
}
@Override
public void makeSound() {
System.out.println(name + " says: Woof-woof!");
}
}
public class Cat implements Movable, Soundable {
private String name;
public Cat(String name) {
this.name = name;
}
@Override
public void move(int x, int y) {
System.out.println(name + " sneaks to (" + x + ", " + y + ")");
}
@Override
public void makeSound() {
System.out.println(name + " says: Meow!");
}
}
Now we can write a universal method to work with any “moving” or “sounding” object:
public static void testMovable(Movable m) {
m.move(10, 20);
}
public static void testSoundable(Soundable s) {
s.makeSound();
}
public static void main(String[] args) {
Dog rex = new Dog("Rex");
Cat murka = new Cat("Mittens");
testMovable(rex); // Rex runs to (10, 20)
testSoundable(murka); // Mittens says: Meow!
}
And of course, if an object implements both interfaces, it can be passed to both!
6. Useful nuances
What if interfaces conflict?
Sometimes two interfaces define methods with the same signature but different meanings. For example, one interface expects that reset() resets coordinates, while another expects the same method to power off a device. In this case, you’ll have to be careful: you still implement the method only once, and it must “handle” both behaviours (or at least make a sensible choice). Such situations are rare in real life, but if you encounter them — it’s worth reconsidering the design.
Example with a collection of objects of different interfaces
Suppose we have a list of objects implementing different interfaces. We can iterate over them and call the required methods:
Movable[] movables = {
new Dog("Spot"),
new Cat("Whiskers"),
new Robot()
};
for (Movable m : movables) {
m.move(0, 0);
}
Similarly, you can do this for any interface.
7. Common mistakes when implementing multiple interfaces
Error #1: not all interface methods are implemented.
If a class declares that it implements an interface but fails to implement at least one of its methods, the compiler will throw an error. Don’t forget all the methods, even if they seem “unnecessary”.
Error #2: conflicting methods with the same signature.
If two interfaces define the same methods, you only implement them once. But if those methods have different meanings, this can lead to confusion and bugs. In that case, it’s better to rethink the architecture.
Error #3: trying to inherit an interface via extends in a class.
In a class, you always use implements to implement an interface, not extends. For example:
public class MyClass implements A, B { ... } // correct
public class MyClass extends A, B { ... } // error!
Error #4: trying to instantiate an interface.
An interface is a contract; it cannot be instantiated directly:
Movable m = new Movable(); // compilation error
You can only create objects of classes that implement the interface.
GO TO FULL VERSION