1. Introducing interfaces

Today is your day for knowledge. Another new and interesting topic is interfaces.

The concept of an interface is the child of the principles of abstraction and polymorphism. An interface is very similar to an abstract class, in which all the methods are abstract. It is declared in the same way as a class, but we use the interface keyword.

interface Feline
{
   void purr();
   void meow();
   void growl();
}

Here are some useful facts about interfaces:

1. Declaring an interface

interface Drawable
{
   void draw();
}

interface HasValue
{
   int getValue();
}
  1. Instead of the class keyword, we write interface.
  2. It contains only abstract methods (don't write the abstract keyword)
  3. In fact, interfaces have all public methods
2. Interface inheritance

An interface can only inherit interfaces. But an interface can have many parents. Another way to say this is to say that Java has multiple inheritance of interfaces. Examples:

interface Piece extends Drawable, HasValue
{
   int getX();
   int getY();
}

3. Inheriting classes from interfaces

A class can inherit multiple interfaces (only from one class). This is done using the implements keyword. Example:

abstract class ChessItem implements Drawable, HasValue
{
   private int x, y, value;
   public int getValue()
   {
      return value;
   }

   public int getX()
   {
      return x;
   }

   public  int getY()
   {
      return y;
   }
}

The ChessItem class is declared abstract: it implements all of the inherited methods except draw. In other words, the ChessItem class contains one abstract method — draw().

The technical meaning of the extends and implements keywords is the same: both are inheritance. The distinction was made to improve the readability of the code. We also say that classes are inherited (via extends) and interfaces are implemented (via implements)

4. Variables

Here's the most important thing: ordinary variables cannot be declared in interfaces (although static ones can).

But why do we need interfaces? When are they used? Interfaces have two strong advantages over classes:



2. Separating the "description of methods" from their implementation.

Previously, we said that if you want to allow the methods of your class to be called from other classes, then your methods need to be marked with the public keyword. If you want some of those methods to be called only from within your class, you need to mark them with the private keyword. In other words, we divide the methods of the class into two categories: "for everybody to use" and "only for our own use".

Interfaces help strengthen this division further. We'll make a special "class for everyone to use" as well as a second class "only for our own use", which will inherit the first class. Here's roughly how it would look:

Before After
class Student
{
   private String name;
   public Student(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
interface Student
{
   public String getName();
}

class StudentImpl implements Student
{
   private String name;
   public StudentImpl(String name)
   {
      this.name = name;
   }

   public String getName()
   {
      return this.name;
   }

   private void setName(String name)
   {
      this.name = name;
   }
}
public static void main(String[] args)
{
   Student student = new Student("Alibaba");
   System.out.println(student.getName());
}
public static void main(String[] args)
{
   Student student = new StudentImpl("Ali")
   System.out.println(student.getName());
}

We split our class into two: an interface and a class that inherits the interface. And what is the advantage here?

Many different classes can implement (inherit) the same interface. And each one can have its own behavior. For example, ArrayList LinkedList are two different implementations of the List interface.

Thus, we hide not only the various implementations, but also the implementing class itself (since we only need the interface in the code). This lets us be very flexible: right as the program running, we can replace one object with another, changing an object's behavior without affecting all the classes that use it.

This is a very powerful technique when combined with polymorphism. For now, it is far from obvious why you should do this. You first need to encounter programs with dozens or hundreds of classes in order to understand that interfaces can make your life so much easier than without them.


3. Multiple inheritance

In Java, all classes can only have one parent class. In other programming languages, classes can often have multiple parent classes. This is very convenient, but also brings many problems.

Java's creators arrived at a compromise: they forbade multiple inheritance of classes, but allowed multiple inheritance of interfaces. An interface can have multiple parent interfaces. A class can have multiple parent interfaces but only one parent class.

Why did they ban multiple inheritance of classes but allow multiple inheritance of interfaces? Because of so-called diamond inheritance problem:

Multiple inheritance

When the B class inherits the A class, it does not know anything about the C and D classes. So it uses the variables of the A class as it sees fit. The C class does the same: it uses the variables of the A class, but in a different way. And all this results in a conflict in the D class.

Let's look at the following simple example. Let's say we have 3 classes:

class Data
{
   protected int value;
}
class XCoordinate extends Data
{
   public void setX (int x) { value = x;}
   public int getX () { return value;}
}
class YCoordinate extends Data
{
   public void setY (int y) { value = y;}
   public int getY () { return value; }
}

The Data class stores the value variable. Its XCoordinate descendant class uses that variable to store the x value, and the YCoordinate descendant class uses it to store the y value.

And it works. Separately. But if we want the XYCoordinates class to inherit both the XCoordinate and YCoordinate classes, then we get broken code. This class will have the methods of its ancestor classes, but they will not work correctly, because they have the same value variable.

But because interfaces cannot have variables, they cannot have this kind of conflict. Accordingly, multiple inheritance of interfaces is allowed.