Inheritance
Inheritance lets a class build on another: the subclass gets the superclass's fields and methods, and can add new ones or change inherited ones.
class Animal {
String name;
Animal(String name) {
this.name = name;
}
void eat() {
System.out.println(name + " is eating.");
}
void speak() {
System.out.println(name + " makes a sound.");
}
}
class Dog extends Animal {
Dog(String name) {
super(name); // run Animal's constructor
}
void fetch() { // a new method that only dogs have
System.out.println(name + " fetches the ball!");
}
@Override
void speak() { // replaces the inherited version
System.out.println(name + " barks.");
}
}
public class Main {
public static void main(String[] args) {
Dog rex = new Dog("Rex");
rex.eat(); // inherited from Animal
rex.speak(); // overridden in Dog
rex.fetch(); // only in Dog
}
}super
super(...)calls the parent's constructor, and must be the first statement in the subclass constructor. If you don't write one, Java insertssuper()for you, which fails to compile when the parent has no constructor without parameters.super.method()calls the parent's version of a method you've overridden:
class Employee {
String name;
double salary;
Employee(String name, double salary) {
this.name = name;
this.salary = salary;
}
double monthlyPay() {
return salary / 12;
}
String describe() {
return name + " earns " + Math.round(monthlyPay()) + " a month";
}
}
class Manager extends Employee {
double bonus;
Manager(String name, double salary, double bonus) {
super(name, salary);
this.bonus = bonus;
}
@Override
double monthlyPay() {
return super.monthlyPay() + bonus / 12; // normal pay, plus the bonus
}
}
public class Main {
public static void main(String[] args) {
Employee e = new Employee("Ada", 1200000);
Manager m = new Manager("Grace", 2400000, 600000);
System.out.println(e.describe());
System.out.println(m.describe());
}
}Manager never wrote a describe method; it inherited one. Yet for Grace, describe calls the Manager version of monthlyPay, because the object is a Manager. That's polymorphism, the subject of the next lesson.
@Override
@Override asks the compiler to check that you really are overriding a parent's method. Misspell the name, say speek(), and instead of silently creating a new method that nothing calls, the compiler reports an error. Always use it.
Every class extends Object
A class without extends still has a parent: Object, which supplies toString(), equals() and hashCode() to every class.
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
@Override
public boolean equals(Object other) {
if (!(other instanceof Point)) return false;
Point p = (Point) other;
return x == p.x && y == p.y;
}
@Override
public int hashCode() {
return 31 * x + y;
}
}
public class Main {
public static void main(String[] args) {
Point a = new Point(2, 3);
Point b = new Point(2, 3);
System.out.println(a); // (2, 3)
System.out.println(a == b); // false: different objects
System.out.println(a.equals(b)); // true: equal values
}
}Object's own equals only checks whether two references are the same object. Override it to compare values, and always override hashCode alongside it, or HashMap and HashSet will misbehave with your class.
The rules
- A class can extend only one class. (It can implement several interfaces, which come two lessons from now.)
- A
finalclass can't be extended at all;Stringis one. - A subclass can't see its parent's
privatemembers.protectedmakes a member visible to subclasses.
When to use inheritance
Use extends for a genuine "is a" relationship: a Manager is an Employee. When the relationship is "has a" (a Car has an Engine), give the class a field instead. That's called composition, and it's usually the more flexible choice.