Interfaces

Recall from last year

Inheritance allows us to abstract over a set of classes that have similar structure and behavior.

Example

public class Shape {
  public void draw(Graphics g) { ... }
  public double area() { ... }
  public Point centroid() { ... }
  public double distanceTo(Shape other) { ... }
}

public class Circle extends Shape { ... }
public class Triangle extends Shape { ... }
public class Rectangle extends Shape { ... }

Shape is an abstraction for different kinds of shapes.

Overriding methods

When a subclass defines a method with the same signature as one defined in its superclass.

When that method is invoked on an instance of the subclass, the method defined in the subclass is run rather than the one in the superclass.

When methods take on many forms, what is the fancy word for it?

Polymorphism. From the Greek “poly” meaning “many” and “morph” meaning “form”, so “many forms”.

Two reasons to override a method

  • To augment the behavior of the superclass.

  • To fill in behavior of a method in a specific way.

Those are two pretty different reasons

Interfaces are for when we just care about the second one.

But what if there’s no good implementation?

Every Shape should have an area method but there’s no useful implementation that we can provide in Shape if it’s a class.

Shape should be an interface

Shape is an abstraction for different shapes but there’s not really a way to define any of those methods for a generic shape so it doesn’t really make sense as a class.

Mechanics

public interface Shape {
  public void draw(Graphics g);
  public double area();
  public Point centroid();
  public double distanceTo(Shape other);
}

Use the keyword interface rather than class.

Instead of a a method body in {}s, after the method signature put a ;.

Classes can implement an interface.

public class Circle implements Shape { ... }
public class Triangle implements Shape { ... }
public class Rectangle implements Shape { ... }

Use implements rather than extends.

It is possible to implement more than one interface. Just separate the names with commas: implements A, B, C.

Interfaces

Interfaces exist solely to allows us to abstract over a set of classes that have similar behavior without regard to their structure.

Differences between classes and interfaces

Classes Interfaces
Can have instance variables Cannot have instance variables
Have constructors Don’t have constructors
A class can only extend one class A class can implement many interfaces
Specify structure and behavior Specify only behavior

Learn to think in intefraces

Even more than classes, interfaces purely define a type.

Anywhere you can use a type (declaring a variable, an array type, a method or constructor parameter, or as the type parameter in a generic type) you can use an interface.

As a variable type

private Shape s = new Circle(0, 0, 100);

private Shape[] shapes = new Shape[10];

s can hold an instance of any class that implements Shape.

shapes is an array that can hold ten instances of any classes that implement Shape.

As parameter types

private int compareByArea(Shape a, Shape b) {
  return (int) Math.signum(a.area() - b.area());
}

This method accepts two arguments that can be instances of any class that implements Shape. (Not necessarily the same class).

The code can call the area() method on them because it’s a method in the interface.

In a generic type

private List<Shape> shapes = new ArrayList<>();

Two for the price of one! List is an interface that captures the notion of a list of things of which ArrayList is a concrete implementation.

And the type parameter Shape is also an interface.

So the value of shapes will be an instance of a class that implements List and all the items in the list will be instances of classes that implement Shape.

Modern ammenities

Originally interfaces were just a collection of methods and constants (static final variables).

These days interfaces can have default methods which contain actual code.

But default methods can only be written in terms of other methods in the interface.

Default method

public interface Shape {
  public void draw(Graphics g);
  public double area();
  public Point centroid();

  public default double distanceTo(Shape other) {
    return centroid().distance(other.centroid());
  }
}

Assuming distanceTo returns the distance between the centers of mass of two shapes, it can be defined in terms of the centroid method.

Interfaces as contracts

Beyond just the information in the method signatures, the point of an interface is to specify a contract that code that uses the interface can rely on and that implementations of the interface must satisfy.

Think about:

  • Preconditions

  • Postconditions

Some important interfaces

java.lang.Runnable

Used to represent a task that can be run requiring no arguments.

Only one method: public void run()

java.lang.Comparable<T>

Implemented by classes that have a natural ordering such as String.

Only one method: int compareTo(T o).

Used by Collections.sort(List<T>) and Arrays.sort(Object[])

Has an interesting contract. “This interface imposes a total ordering on the objects of each class that implements it.”

java.util.List

The interface implemented by java.util.ArrayList and other classes.

Captures the idea of a sequential, ordered list of elements. Can contain duplicate elements.

Some Lists are immutable.

List.of() returns an immutable list of its arguments. We don’t even know what class it is.

Interfaces can extend each other

Interfaces can extend other interfaces and add methods.

And a single interface can extends multiple other interfaces, creating an interface with the union of all the other intefaces’ methods plus any added in the new interface.

Example

public interface PriorityTask
  extends Runnable, Comparable<PriorityTask> {

  public double getPriority();

}

Any class that implements this interface will be a Runnable and also Comparable with other PriorityTasks.