Interfaces in Java are much like any other language. They are a contract which states the behaviours (methods) an implementing Class must have.

Declaration

interface MyContract{
	// interface fields MUST be public static final
	public static final String someConstant = "constant field"
	String someOtherConstant = "fields are implcitly public static final"
	
	// interface methods can only be public and have no body
	public void someBehaviour1();
	String someBehaviour2(String a); // public by default
	
	// static methods must have a body and can only be private or public
	static void staticBehaviour1() { // public by default
		System.out.println("helper method");
	}
	private static void staticBehaviour1() { // for implementing class only
		System.out.println("helper method");
	}
	
	// but, they can have a body if they are default
	default String defaultBehaviour1(int a) {
		return String.valueOf(a);
	}
}

Fields must be public static final

Why public?:
Interfaces are contracts. All parts of a contract must be accessible/visible to be of any use!

Why static?:
Interfaces can’t be instantiated, so its fields have to be static.

Why final?:
Interrrffaacesss areee contracttttsss. Contracts shouldn’t change!

Generally, methods must be public and have no body (they are public by default)

Well, the point of interfaces is to describe a set of behaviours that a class must exhibit. So it wouldn’t make sense for there to be methods that are private or protected…
The same reasoning applies to why the methods have no body, it is not the job of the interface to implement the behaviour, it merely enforces the behaviour’s existence.

static methods! (MUST HAVE BODY)

These are used to provide helper methods that are related to the Interface.
They can only be public (default) or private, and must have a concrete implementation.

private methods (MUST HAVE BODY)

These are for static or default methods, so they can be split and organised into smaller methods for reuseability/readability.

What about default methods? (MUST HAVE BODY)

Allowing implementation to be defined in the interface with the default keyword seems to be antithetical to the purpose of Interfaces that we just discussed.
SO why can Interfaces have default methods?
It’s so Interfaces can be updated to require new methods without having to update ALL the downstream Classes that use the Interface to include those new methods.

Let’s say we are developing a product and start with a pretty simple Interface to be used by Classes that can represent themselves as an image bitmap:

interface Drawable {
	Image draw();
}

Over time, our requirements changed, and in newer code, we also require Classes that are Drawable to also be able to give us a name so that the save image file dialog can give the file a sensible default name.

interface Drawable {
	Image draw();
	String getName();
}

But now you have to go back into your old code and modify every Class in your codebase that uses this Interface.
Implementing the getName() method despite it not being used by the old code at all.

This is where default is used!!

interface Drawable {
	Image draw();
	default String getName() {
		throw new UnsupportedOperationException("Not yet implemented");
	}
}

With default, you can add new methods to the Interface without breaking older code!

Inheriting an Interface

Java Interface Inheritance

  • Interface Inheritance creates an “has-a” relationship
  • Each Class can implement any number of Interfaces
  • Fields can only be, and are public static final by default
  • Methods are public by default and can explicitly be private (>= Java 9)
  • Methods are only signatures and have no implementation body unless they are static or default
  • Methods can be static or default which require concrete implementation. see here

Purpose:

Interfaces in Java actually have 2 main purposes !!

Behavioural/Contractual Interfaces

Interfaces are often described as contracts. While classes describe a whole ‘thing’, Interfaces only describe behaviour. A Cat should be described by a class, it has properties like hungerLevel and behaviour like eat() that relate to each other. But we could implement an Interface called Trained which describes behaviours like Sit() or RollOver(). Now our Cat is able to sit and roll-over! But of-course, these behaviours are not exclusive to Cat, they can be implemented by Dog, Cow… whatever! That’s the point of interfaces. To assign specific shared behaviours you want your classes to have.

A key example of a Behavioural Interface from the Java standard library is Comparable<T>.
This Interface defines the behaviour/method int compareTo(T o) which the implementing Class then has to Override, giving it the behaviour of being comparable!
int compareTo(T o) is used by an object to compare itself to another object. Giving objects of this Class a natural order.

The Collections Class in Java, defines a method named sort which has the following signature:

public static <T extends Comparable<? super T>> void sort​(List<T> list)

This is a generic method using generic wildcards to express that its parameter List<T> list can only take in a List which has elements that have a natural order, which is required for the sorting algorithm. It does this by enforcing the generic T of the list must be of a type/Class that implements Comparable<T>.

So, by implementing the Comparable<T> Interface, we will have given the Class and its objects a natural order which will allow us to sort it by calling Collections.sort(List<T> list).

Functional Interfaces

It is often useful to be able to pass some logic into a function. Especially when it comes to sorting.
Perhaps the objects I am sorting have no natural order (doesn’t implement Comparable<T>), or I want to define my own custom order!

This is where Functional Interfaces come into play! Unlike Behavioural Interfaces, these interfaces are used solely to pass functions around. They should not be implemented by a Class, as they are meant to represent a function on its own, and not a behaviour that a Class can exhibit.
Instead, they should be implemented with the lambda syntax or method reference.

The Functional Interface from the Java standard library Comparator<T> is what is used for implementing a custom sorting order.
This Functional Interfaces defines the method int compare(T o1, o2) which compares two objects of the same Class/type, allowing us to define the order of objects of a Class Student separately from the code in that Class.

The Collections Class in Java, also defines another method named sort which has the following signature:

public static <T> void sort(List<T> list, Comparator<? super T> c)

This is also a generic method using generic wildcards. However, instead of restricting the generic T to be of a type that has natural order (implements Comparable).
This method allows us to pass in a List<T> list of any type, but we must also supply Comparator<? super T> c, which is an implementation of Comparator<T> that is compatible with the type of the elements in the List<T> list.

So, by supplying an implementation of Comparator<T> to Collections.sort(List<T>, Comparator<? super T> c) we can sort any list of any elements in any way we want, even if the element itself is not of a type that has natural order.

Link to original

Types of Interfaces