Inheritance is a yet another form of abstraction.
(Yeah, we only have one big idea in computer science.)
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 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 abstract a set of computations over related values.
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.
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
in an abstraction for a number of different kinds
of shapes.
extends
public class GridGame extends JPanel {}
public class TicTacToe extends GridGame {}
This establishes an is-a relationship, as in tic tac toe is a grid game.
GridGame
is called the “parent class” or “super class”.
TicTacToe
is called the “child class” or “subclass”.
(GridGame
also has a parent class, namely
JPanel
.)
extends
Any class without an explicit extends
clause implicitly
extends java.lang.Object
.
This is why every class has a toString
and
equals
method even if we don’t write them.
Recall that the role of constructors is to make sure an instance is property initialized and ready to be used.
A GridGame
has to have its rows, columns, and padding
initialized so it has a constructor that takes those as arguments.
public GridGame(int rows, int columns, int padding) {
this.rows = rows;
// etc.
}
super
Since a TicTacToe
is a GridGame
it also
must initialize those things.
We can use super
to invoke the code of the
GridGame
constructor.
public TicTacToe() {
super(3, 3, 4);
// rest of constructor
}
Variables are inherited but if they are private
they
are still not directly accessible in the subclass.
But every instance of the subclass does have those variables and they will be used by methods inherited from the super class.
Methods are inherited which means any method you can call on an instance of the super class you can also call on an instance of the subclass.
The subclass can define its own variables and methods that don’t make sense in the super class.
public class TicTacToe extends GridGame {
private int move = 0;
public boolean isDraw() { return move == 9; }
}
This is the real power move of inheritance. 💪
A subclass can define a method that has the same signature as an existing method from the super class.
This allows the behavior of different classes to differ based on the class of the object they are invoked on, not just on the arguments.
This goes by the fancy Greek-derived word “polymorphism”, or “many forms”.
As in, the same method in different classes can take on many forms.
toString
Every class in Java has a toString
method.
Many classes override toString
to provide a more useful
human-readable representation of instances of the class.
Object o = new Object();
Object s = "foo bar";
Object n = Integer.valueOf(10);
o.toString() ⟹ "java.lang.Object@4b9af9a9"
s.toString() ⟹ "foo bar"
n.toString() ⟹ "10"
Defined by Barbara Liskov, MIT professor and 2008 Turing Award Winner.
While different classes have different behavior (that’s the whole point), subclass’s behavior should be enough the same that you can substitute an instance of the subclass anywhere you can use an instance of the super class.
Exactly what the same means is a big part of defining your abstraction.
While extending a class means you get some methods for free you should never extend a class unless there is an actual “is-a” relationship between the subclass and the super class.