1. Abilities

To better understand the benefits of interfaces and where to use them, we need to talk about some more abstract things.

A class usually models a particular object. An interface corresponds less to objects, and more to their abilities or roles.

The essence of interfaces

For example, things like cars, bikes, motorcycles, and wheels are best represented as classes and objects. But their abilities — such as "I can be ridden", "I can transport people", "I can stand" — are better presented as interfaces. Here are some examples:

Code Description
interface CanMove
{
   void move(String newLocation);
}
Corresponds to the ability to move
interface Rideable
{
   void ride(Passenger passenger);
}
Corresponds to the ability to be ridden
interface CanTransport
{
   void addStuff(Object stuff);
   Object removeStuff();
}
Corresponds to the ability to transport stuff
class Wheel implements CanMove
{
   ...
}
The Wheel class can move
class Car implements CanMove, Rideable, CanTransport
{
   ...
}
The Car class can move, be ridden, and transport stuff
class Skateboard implements CanMove, Rideable
{
   ...
}
The Skateboard class can move and be ridden


2. Roles

Interfaces greatly simplify a programmer's life. Very often, a program has thousands of objects, hundreds of classes, but just a couple dozen interfaces, i.e. roles. There are few roles, but there are many ways to combine them (classes).

The whole point is that you don't have to write code for in each class to interact with every other class. You just need to interact with their roles (interfaces).

Imagine you are a pet trainer. Each of the pets you work with can have several different abilities. You get into a friendly argument with your neighbor regarding whose pets can make the most noise. To settle the matter, you just line up all the pets that can "speak", and you give them the command: Speak!

You don't care what kind of animal they are or what other abilities they have. Even if they can do a triple back somersault. At this particular moment, you are only interested in their ability to speak loudly. Here's what it would look like in code:

Code Description
interface CanSpeak
{
   void speak();
}
The CanSpeak ability. This interface understands the command to speak, meaning that it has a corresponding method.
class Cat implements CanSpeak
{
   void speak()
   {
      println("MEOW");
   }
}

class Dog implements CanSpeak
{
   void speak()
   {
      println("WOOF");
   }
}

class Fish
{
   ...
}
Animals that have this feature.

To facilitate understanding, we provided the classes names in English. This is allowed in Java, but it is highly undesirable.













Our Fish does not have the ability to speak (does not implement the CanSpeak interface).

public static void main(String[] args)
{
   // Add all the animals to the list
   ArrayList pets = new ArrayList();
   pets.add(new Cat());
   pets.add(new Dog());
   pets.add(new Fish());

   // If the ability exists, then make a sound
   for(Object pet: pets)
   {
      if (pet instanceof CanSpeak)
      {
         CanSpeak loudmouth = (CanSpeak) pet;
         loudmouth.speak();
      }
   }
}
And how do we give them the command?

When the number of classes in your programs reaches the thousands, you will not be able to live without interfaces. Instead of describing the interaction of thousands of classes, it is enough to describe the interaction of a few dozen interfaces — this greatly simplifies life.

And when combined with polymorphism, this approach is generally a smashing success.



3. The default implementation of interface methods

Abstract classes can have variables and implementations of methods, but they cannot have multiple inheritance. Interfaces cannot have variables or implementations of methods, but that can have multiple inheritance.

The situation is expressed in the following table:

Ability/property Abstract classes Interfaces
Variables
Method implementation
Multiple inheritance

So, some programmers really wanted interfaces to have the ability to have method implementations. But having the ability to add a method implementation does not mean that one will always be added. Add it if you want. Or if you don't, then don't.

In addition, problems with multiple inheritance are primarily due to variables. In any event, that's what they decided and did. Starting with JDK 8, Java introduced the ability to add method implementations to interfaces.

Here's an updated table (for JDK 8 and above):

Ability/property Abstract classes Interfaces
Variables
Method implementation
Multiple inheritance

Now for abstract classes as well as interfaces, you can declare methods with or without an implementation. And this is excellent news!

In abstract classes, methods without an implementation must be preceded by the abstract keyword. You don't need to add anything before methods with an implementation. In interfaces, the opposite is true. If a method does not have an implementation, then nothing should to be added. But if there is an implementation, then the default keyword must be added.

For simplicity, we present this information in the following little table:

Ability/property Abstract classes Interfaces
Methods with no implementation abstract
Methods with an implementation default

Problem

Using interfaces that have methods can greatly simplify large class hierarchies. For example, the abstract InputStream and OutputStream classes can be declared as interfaces! This lets us use them much more often and much more conveniently.

But there are already tens of millions (billions?) of Java classes in the world. And if you start changing standard libraries, then you might break something. Like everything! 😛

In order to not accidentally break existing programs and libraries, it was decided that method implementations in interfaces would have the lowest inheritance precedence.

For example, if one interface inherits another interface that has a method, and the first interface declares the same method but without an implementation, then the method implementation from the inherited interface will not reach the inheriting interface. Example:

interface Pet
{
   default void meow()
   {
      System.out.println("Meow");
   }
}

interface Cat extends Pet
{
   void meow(); // Here we override the default implementation by omitting an implementation
}

class Tom implements Cat
{
}

The code will not compile because the Tom class does not implement the meow() method.