Java Interfaces

Java interfaces are a powerful mechanism to implement abstraction. A Java interface normally defines one or more abstract methods – method signatures.

Moreover a Java interface can also contain constants, static methods, and default methods. An interface can also contain no methods. These interfaces are known as marker interfaces.

Introduction To Interfaces

As mentioned an interface can contain a number of methods and constants. Moreover, it can be considered as an abstract type, as it cannot be directly instantiated.

We can create an interface using the interface keyword.

1
2
3
4
5
public interface Warrior {
    public void goToWar();

    public int getNumberOfWars();
}

Above, we create an interface called Warrior. Our interface defines the methods called goToWar, and getNumberOfWars.

An interface is a powerful abstraction tool, as we can define the responsibilities / contract that a type that implements an interface must realize. Moreover, clients that use our Warrior type do not need to be concerned with the specific details of how this Warrior type was implemented. This provides a means to achieve polymorphism and stronger encapsulation.

Implementing An Interface

To implement an interface we use the implements keyword.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
public class Viking implements Warrior {
    private int warsFought;

    public Viking() {
        this.warsFought = 0;
    }

    @Override
    public void goToWar() {
        warsFought++;
    }

    @Override
    public int getNumberOfWars() {
        return warsFought;
    }
}

Above, we create our first Warrior type. We created the Viking class that implements the Warrior interface. Our Viking class must implement all of the abstract methods of the Warrior interface otherwise, it must be declared abstract.

By implementing the Warrior interface our Viking type is now said to have the types: Object, Warrior, and Viking.

Interfaces can be implemented by the following Java types:

  • Java Classes
  • Java Abstract Classes
  • Java Nested Classes
  • Java Enum
  • Dynamic Proxies

Interface Static Methods

An interface can also have static methods. Static methods defined in an interface must have a method body. Static methods were introduced in Java 9.

1
2
3
public boolean hasWarExperience(Warrior warrior) {
    return warrior.getNumberOfWars() > 0;
}

Static methods in interfaces are useful, if you have some utility methods related to the interface type.

Just like a regular static method we can invoke a static method via the interface name.

1
Warrior.hasWarExperience(warrior);

Interface Default Methods

An interface can also have default methods, which were introduced from Java 8. Default methods allow interfaces to contain an implementation of a method. Moreover, all types that implement an interface with default methods, receive an implementation of those methods.

1
2
3
4
5
6
7
public default boolean isWarriorLucky() {
    return getNumberOfWars() > 5;
}

public default boolean isWarriorSkilled() {
    return getNumberOfWars() > 10;
}

Default methods are defined with the default keyword, as shown above. Default interfaces can be used to add default functionality to all types that implement an interface without breaking existing code.

For example, let’s say we want to add a new method to examine a warriors conscience. If we add this method as an abstract method, then it can break existing code, as it will force all warrior types to be modified to implement this method.

However, if we add this method as a default method all warrior types will receive the default implementation. A warrior can then decide to override this method and provide a custom implementation when it needs to. This approach provides for a more graceful evolution of an interface.

1
2
3
4
5
public enum Conscience {
    DO_GOOD,
    DO_EVIL,
    DO_SOMETHING
}
1
2
3
public default Conscience getConscience() {
    return Conscience.DO_SOMETHING;
}

Interface Constants

Interfaces can also define constants. However, placing constants in an interface is only really useful when they add value, such as being used in classes that implement the interface.

1
2
3
4
public interface Warrior {
    String warriorVersion = "1.0";
    public static final Conscience DEFAULT_CONSCIENCE = Conscience.DO_SOMETHING;
}

In general we shouldn’t place constants in an interface.

Interface Rules

Let’s quickly review the rules for creating interfaces.

  • Interfaces are inherently abstract, they can’t be instantiated directly.
  • All variables defined within an interface are implicitly constants.
  • An interface can have no methods in this case it is known as a marker interface.
  • An interface cannot be defined with the final keyword.
  • All method signatures defined inside an interface are implicitly public and abstract. There is no need to use the public, or abstract keyword.
  • Interfaces can extend from one or more interfaces using the extends keyword.
  • Interfaces can also be generic and define type parameters.
  • Interfaces can be nested inside of other interfaces.
  • An interface can be defined with the access modifiers: public, private, protected, package protected (default).
  • Java 8 introduced the possibility to define default methods in an interface.
  • From Java 9 we can define static, private static, and private methods in an interface.

Interfaces And Inheritance

Firstly a Java interface can inherit from another interface. This can be achieved using the extends keyword.

1
2
3
public interface Magician extends Warrior {
    public void castSpell();
}

The interface Magician extends the Warrior interface. This means that the Magician interface inherits all the members of the Warrior interface. Moreover, any type that implements the Magician interface must provide implementations for the abstract methods defined in both interfaces.

Multiple Inheritance

Interfaces can also extend from multiple interfaces. This is achieved by separating the interface with a comma after the extends keyword.

1
2
3
public interface Magician extends Warrior, Comparable<Magician> {
    public void castSpell();
}

Java classes are not allowed to extend from multiple classes. Therefore, Java supports singular inheritance. However, Java supports a form of multiple inheritance through interfaces.

Just like an interface, a Java class can implement multiple interfaces by placing a comma separated list of interface names after the implements keyword.

1
2
3
public interface Vitality {
    public int getVitality();
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class Viking implements Warrior, Vitality {
    private int warsFought;

    public Viking() {
        this.warsFought = 0;
    }

    @Override
    public void goToWar() {
        warsFought++;
    }

    @Override
    public int getNumberOfWars() {
        return warsFought;
    }

    @Override
    public int getVitality() {
        return 50;
    }
}

Above the Viking class implements both the Warrior and Vitality interfaces. Therefore, the Viking class must provide an implementation of all the abstract methods defined in both interfaces. Otherwise, the Viking class must be marked as abstract.

Inheritance And Default Methods

Default methods that were introduced from Java 8, must be explicitly implemented in some scenarios when used with interface inheritance. As we saw, a class can easily implement multiple interfaces.

However, if a class implements multiple interfaces that each declare a default method with the same signature. The implementing class must override the default method and provide a custom implementation.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public interface Peasant {

    public default Conscience getConscience() {
        return Conscience.DO_GOOD;
    }
}

public interface Warrior {
    public default Conscience getConscience() {
        return DEFAULT_CONSCIENCE;
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class FightingPeasant implements Warrior, Peasant {

    @Override
    public void goToWar() {
    }

    @Override
    public int getNumberOfWars() {
        return 0;
    }

    @Override
    public Conscience getConscience() {
        return Conscience.DO_GOOD;
    }
}

Above the class FightingPeasant implements the interfaces Warrior and Peasant. Since both of these interfaces each define the default method getConscience() the FightingPeasant class must provide a custom implementation of this method, because the Java compiler cannot decide by itself which one to use.

Interfaces And Polymorphism

Java interfaces provide a flexible mechanism to achieve polymorphism. Polymorphism allows a type to act as different types in different contexts, by fulfilling the contract of a particular type.

So, we say an object can take on different forms during runtime. This is achieved by inheritance, overriding a method from a parent class, or by implementing an interface.

For example let’s say we want to include a Dog in our army.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class Dog implements Warrior {

    @Override
    public void goToWar() {
        System.out.println("Dog gone to war");
    }

    @Override
    public int getNumberOfWars() {
        return 0;
    }
}

So now, we have three unrelated types, Viking, FightingPeasant, and Dog. However, all three types implement the Warrior interface. Therefore, we can consider all of these types as Warrior types, as they fulfill the contract expressed through the Warrior interface.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
public static class Army {
    private List<Warrior> warriors = new LinkedList<>();

    public Army() {
        warriors.add(new Viking());
        warriors.add(new FightingPeasant());
        warriors.add(new Dog());
    }

    public void goToWar() {
        for (Warrior warrior : warriors) {
            warrior.goToWar();
        }
    }
}

Above we create an Army class that contains a collection of warriors. The collection is made up of Viking, FightingPeasant, and Dog types. However, we refer to them all as Warrior types. Therefore, we don’t care what specific types our army contains, as long as they are warriors.

We then use polymorphism to send them all to war.

1
2
3
4
5
public void goToWar() {
    for (Warrior warrior : warriors) {
        warrior.goToWar();
    }
}
1
2
3
public static void main(String[] args) {
    new Army().goToWar();
}
1
2
3
Viking gone to war
FightingPeasant gone to war
Dog gone to war

Abstract Classes And Interfaces

Abstract classes can also implement interfaces. However, unlike regular classes abstract classes are not required to implement all the methods of an interface.

Moreover, an abstract class is normally used to provide a default implementation of a number of interface methods, to share common code between concrete classes.

1
2
3
4
5
6
7
public abstract class BaseWarrior implements Warrior {
    protected int warsFought;

    public int getNumberOfWars() {
        return warsFought;
    }
}

Generic Interfaces

An interface can also be generic. A generic interface can accept type parameters, thus making it work with different Java reference types.

Generic interfaces are used throughout the Java API.

1
2
3
public interface Comparable<T> { }

public interface Collection<E> extends Iterable<E>

You can read more about generics in the tutorial An Introduction To Java Generics.

Functional Interfaces

Functional interfaces were introduced in Java 8. A functional interface is an interface which requires a single method.

Functional interfaces were created to work with lambda expressions.

1
2
3
4
@FunctionalInterface
public interface Consumer<T> {
    void accept(T t);
}

Above is the standard Java functional interface Consumer, that is used to consume a value.

This interface can then be used as a lambda expression.

1
warriors.forEach((w) -> w.goToWar());

Conclusion

In this tutorial we examined interfaces in Java. We looked at how they can be used, some of their rules, and some of the advantages that they offer.