Java Interface
Abstract class and interface are both tools to achieve abstraction that allow us to declare abstract methods. We cannot create instances of abstract classes and interfaces directly, instead we can only create such instances through classes that inherit them. Abstract classes and interfaces have a lot of other differences but the main one is their purpose.
Typically, an interface is used to decouple the interface of a component (class) from the implementation while abstract class are often used as base class with common fields to be extended by subclasses.
Multiple inheritance
What if we want a class to inherit from multiple interfaces. The use case is simple: animals of class amphibians can live both in water and on land so all of them must have some characteristics from these kinds. This is called multiple inheritance.
interface Fish { }
interface Terrestrial { }
class Amphibian implements Fish, Terrestrial { }
Or if we know beforehand that we will need to create multiple classes from a class with multiple inheritance, we can create a new interface that will extend one or more other interfaces using the extends
keyword:
interface Fish { }
interface Terrestrial { }
interface Amphibian extends Fish, Terrestrial { }
In case you need to combine some properties, a class can also extend another class and implement multiple interfaces like this:
class A { }
interface B { }
interface C { }
class D extends A implements B, C { }
Multiple inheritances of interfaces are also often used in the Java standard class library. The String
class, for example, implements three interfaces at once:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
// ...
}
Now let's discuss method types. There are three: abstract, default, and static.
Abstract methods
So by default, if we do not provide a method with a body, it will be abstract. Meaning it can only have a declaration, not a definition. They must be defined later in the implementing classes though. Here is a simple interface example with an abstract method named breathe:
interface Fish {
abstract void breathe();
}
You can omit the abstract
keyword as it is optional.
Default methods
Default methods are defined with the default
modifier. It means that these methods can be accessible from classes implementing the interface:
interface Fish {
default void breathe(){
System.out.println("A breath was taken!");
}
}
Static methods
In addition to default methods, you can declare and implement a static method in an interface via the static
keyword.
You can use these methods by invoking it directly from an interface:
interface Car {
static double convertToMilesPerHour(double kmh) {
return 0.62 * kmh;
}
}
Car.convertToMilesPerHour(4.5);
The main purpose of static methods is to define utility functionality that is common for all classes implementing the interface. They help to avoid code duplication and create additional utility classes. For example the System.out.println
is also a static method.
Marker interfaces
In some situations, an interface has no members at all. Such interfaces are called marker or tagged interfaces. For example, a well-known interface — Serializable
, is a marker interface:
public interface Serializable {
}
Other examples of marker interfaces are Cloneable
, Remote
, etc. They are used to provide essential information to the JVM.
Functional interfaces
In all the interfaces above, we implied the methods implementation.
The interfaces with only one abstract method and any number of static, default, and public are called functional; otherwise, we will call interfaces with multiple abstract methods normal.
There is also the @FunctionalInterface
annotation that ensures the interface has only one abstract method although using this annotation is not mandatory. The restriction needs to be respected for the sake of properly working lambda functions.
interface Fish {
void breathe();
}
A typical functional interface example from the default library is ActionListener which only contains the actionPerformed()
method.
Access modifiers
In the previous part, we briefly used public access modifiers with interface methods. Let's talk about all possible modifiers a method can have in the interface.
In the latest Java versions (after 9th), we can define:
- public — a method that can be used from any class or package;
- private — a method that can be accessed only from the same interface. Also can be used with static.
Note that all methods are public by default.
And finally, let's sum up all the options for interface contents in this example:
An interface can't contain constructors, non-public abstract methods, or any fields other than public static final
(constants). Let's declare an interface containing all possible members:
interface Interface {
int INT_CONSTANT = 0; // it's a constant, the same as public static final int INT_CONSTANT = 0
void instanceMethod(); // An abstract methot
static void staticMethod() {
System.out.println("Interface: static method");
}
private static void staticPrivateMethod() {
System.out.println("Interface: private static method");
}
default void defaultMethod() {
System.out.println("Interface: default method. It can be overridden");
}
private void privateMethod() {
System.out.println("Interface: private methods in interfaces are acceptable but should have a body");
}
}