Interfaces

Abstraction review

We’ve learned about three kinds of abstraction:

  • Variables
  • Methods
  • Classes

Variables

Variables abstract values.

When we define a variable we are defining the idea of how a whole set of values can be used.

int speed; // The speed something is moving.
String name; // Something's name.

At different times the variable will hold different values but in an abstract sense it will always represent the same thing.

Methods

Methods abstract computations.

public int distance(Point a, Point b) {
  return Math.hypot(a.x - b.x, a.y - b.y);
}

Each call to a given method with different arguments does something different.

But the differences have been abstracted away so we can talk about “what the method does”.

Classes

A class defines instance variables, constructors, and methods.

It defines an abstraction over all objects with that particular shape (defined by the instance variables) and behavior (methods).

Class example

public class Student {
  private String name;
  private int grade;
  private ArrayList<Course> courses;

  public double gpa() { ... }
  public int creditsEarned() { ... }
  // etc.
}

Every instance of a class has its own state but all instances have the same set of methods, abstractly defining what we can do with those instances.

Classes are too concrete

A well-designed class’s instance variables are almost always private.

So from the abstract view we only care about a class’s methods.

Why tie ourselves down?

Intefaces

Abstracting classes

Shape

Suppose we want to represent shapes we can manipulate and draw on the screen. We might want these methods that define what we can do with a shape.

public void draw(Graphics g)
public double area()
public Point centroid()
public void moveTo(Point p)

But there’s not really a way to define most of those methods for a generic shape, so it doesn’t really make sense as a class.

Interfaces

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

Mechanics

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

Use the keyword interface rather than class.

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

Like a class

  • Defines a new type we can use in declarations
  • Defines a set of methods we can call on objects of that type

Unlike a class

  • Doesn’t define instance variables
  • Doesn’t define constructors
  • Cannot, in fact, be constructed

Using an interface

To use an interface we need a class that implements that interface.

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

An implementation

public class Circle implements Shape {

  private Point center;
  private int r;

  public Circle(int x, int y, int r) {
    this.center = new Point(x, y);
    this.r = r;
  }

  public void draw(Graphics g) {
    g.drawOval(center.x - r, center.y - r, 2 * r, 2 * r);
  }

  public double area() { return Math.PI * r * r; }

  public Point centroid() { return center; }

  public void moveTo(Point p) { center = p; }
}

Differences between classes and interfaces

Classes Interfaces
Can have instance variables Cannot have instance variables
Have constructors Don’t have constructors
Specify structure and behavior Specify only behavior

Polymorphism

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

This is the power move of object orientation.

for (Shape s : shapes) {
  s.draw(g);
}

The code that runs each time draw is called is determined by the actual class that each Shape is an instance of.

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 differenceInArea(Shape a, Shape b) {
  return 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 amenities

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 void moveTo(Point p);

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

The distanceTo method can compute the distance between the centers of mass of any two shapes since all shapes have a 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.

Which means any such class will need to provide run and compareTo methods as well as getPriority.