Contents
As a concept & a Java keyword
In Java and OOP as a whole, there are two traditional meanings for the term interface. On one hand, we mention interface when we describe polymorphism - one interface, multiple methods, this is the concept-level interface; on the other hand, interface
is a valid Java keyword, and through multiple JDK iterations, interface
is now working in a very similar way as class
, with a few but crucial differences.
KEYWORD - Interface
Definition: An interface
is declaring the methods without defining any method body. In other words, it specifies what needs to be done, but not how to do it, which is classes` responsibility. An example would look like this:
public interface myIF{
void meth1(int param1);
void meth2(String param2);
int meth3();
}
This is an interface
in its most traditional sense, where no method body is defined, all signatures are directly followed by a semicolon.
For a class to follow, or conform, the blueprint declared by an interface, we need another keyword:
KEYWORD - implements
implements
is an optional keyword in a class declaration, in a similar sense like extends
. implements
allows the class to actually define the method bodies in the interface, providing a separate hierarchy from inheritance. Unlike inheritance where a class can only inherit from at most one superclass, a class is allowed to implement multiple interfaces.
A class that implements an interface must define the body for all the methods in the interface and the methods must be public, otherwise this class must be declared as abstract
. An example of a non-abstract class would look like this:
public class myClass implements myIF{
public myClass(){
}
// methods from myIF
public void meth1(int param1){
System.out.println("meth1 from myClass");
}
public void meth2(String param2){
System.out.println("meth2 from myClass");
System.out.println(param2);
}
public int meth3(){
return 0;
}
// other methods unaccessible from myIF...
public void meth4(){
}
//...
}
UML
In UML, an interface usually has a circle or simply <<interface>> at the name row, and the implements
relationship is illustrated by a dashed arrow.
Interface references
Just like inheritance, where you can have superclass reference variables referencing subclass objects, here you can also have interface reference variables referencing implementing class objects. The method binding, again, is dynamic. That is, the determination of which version of method to call is performed at runtime.
This is useful because it allows you to use the interface without worrying about any implementation details. That is, an interface can have multiple implementations at the same time. Moreover, changing the implementation in the future won’t affect the interface reference, which enables compatibility and more robust code.
KEYWORD - default
default
is one of those keywords that make interfaces “less pure”: methods with default
in their declaration can have a method body in the interface. As the word suggests, this is meant to provide a default implementation for the method, so that the implementing classes have the freedom to choose to either override the method or simply leaving it.
default
is there for two purposes:
- An interface can be expanded without affecting existing code. Without
default
, I would need to manually go through all the implementations and add duplicate code, which is certainly less robust and poor OOP design. - An interface can provide optional methods for classes. In this case, I can include a default method that raises an exception, so the implementing classes can choose whether to override this with a valid method body or not. Without
default
, I would need to manually define a placeholder method in the class, which is redundant.
Note that when it comes to exceptions, inheritance is unlike association where an exception is either passed or caught in methods. In inheritance, you can actually override a method that throws an exception with one that does not do so, and dynamic binding will resolve the issue for you.
KEYWORD - static
static
has also become a valid keyword in interfaces. Just like in classes, static
methods in interfaces cannot be overridden or inherited.
Declaring variables in interfaces
You can, actually, declare variables in interfaces, and they are treated by default, as public
, static
and final
, giving them a responsibility as a constant. But creating an interface as a pure collection of constants is definitely not a good OOP design, for two reasons:
- Constants are considered as implementation details;
- Having one interface full of constants, and importing them using
implements
can pollute an entire chain of inheritance: the subclassesimplements
the interface by default, even if the subclasses don’t make use of any of the constants at all, or if the subclasses want to have a constant of the same name but a different value, it can’t do that because the namespace has already been taken by the interface.
As a result, collection of constants are better to be declared as classes and be made use of via association.
Moreover, This whole “static methods + default methods + the original intent of interfaces” can give you an illusion that interfaces can replace abstract classes. Although you can probably achieve this in practice, this is considered bad design. Firstly, the interface is used for only one purpose: specify what but not how. That is, interface should touch the implementation details as little as possible. Hence, replacing classes with interfaces violates this rule and is therefore not recommended.