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();
}
- Instead of the
class
keyword, we writeinterface
. - It contains only abstract methods (don't write the
abstract
keyword) - In fact, interfaces have all
public
methods
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 |
---|---|
|
|
|
|
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:
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.
GO TO FULL VERSION