Inheritance allows us to abstract over a set of classes that have similar structure and behavior.
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.
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.
Polymorphism. From the Greek “poly” meaning “many” and “morph” meaning “form”, so “many forms”.
To augment the behavior of the superclass.
To fill in behavior of a method in a specific way.
Interfaces are for when we just care about the second one.
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
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.
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 ;
.
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 exist solely to allows us to abstract over a set of classes that have similar behavior without regard to their structure.
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 |
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.
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
.
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.
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
.
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.
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.
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
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 List
s are immutable.
List.of()
returns an immutable list of its arguments. We don’t even know what class it is.
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.
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 PriorityTask
s.