Before we discuss what inheritance is in code, let’s talk about what it means in real life. We often inherit our traits and behaviors from our parents through our genes or the way they raise us. People can also inherit belongings through wills. In programming, inheritance works the same way. A class (a subclass or child class) that inherits another class (a superclass or parent class) is able to use its methods and fields (assuming they aren’t private).

Inheritance is useful in programming because it describes an is-a relationship. For example, I could have a superclass called Instrument. The subclasses Guitar, Piano, and Flute could all inherit from Instrument because Guitars, Pianos, and Flutes are Instruments.

Inheritance which allows for greater abstraction because the fields and methods that are common to all instruments can be defined in the Instrument class, while the fields and methods specific to Guitars, Pianos, and Flutes are only defined in their respective classes.

For instance, it doesn’t make sense to have a field called numberOfStrings in the Flute class, but it does make sense for it to be in the Guitar class. Similarly, since both Guitars and Flutes can be played, it would make sense to have a play() method in the Instrument class since all instruments can be played.

So how do you actually express inheritance using Java syntax? You need to use the extends keyword to signify that the class inherits from a superclass. For example

class Guitar extends Instrument {
		// *class body*
}

<aside> 💡 Note: A subclass can only extend 1 superclass, so design your classes carefully!

</aside>

Super Keyword

Recall that the this keyword is used to refer to the current object. There’s also another handy keyword called super which allows you to refer to the superclass. Specifically, you can use it to call superclass methods (including the superclass constructor) and access superclass fields.

Analyze the following code, for example. Pay attention to the highlighted parts.

public class TestInstrument {

    public static void main(String[] args) {
        // *construct a new Guitar object*
        Guitar taylorGuitar = new Guitar("acoustic", "steel");

        // *print the Guitar object*
        System.out.println(taylorGuitar);

        // *prints "Playing instrument" 6 times*
        taylorGuitar.strum();
    }
}

class Instrument {

    private String name;

    public Instrument() {
        name = "";
    }

    public Instrument(String name) {
        this.name = name;
    }

    public void play() {
        System.out.println("Playing instrument");
    }

    @Override
    public String toString() {
        return "Instrument, name: " + name;
    }
}

class Guitar extends Instrument {

    private String type;
    private String stringType;

    public Guitar() {
        super("guitar");
        type = "acoustic";
        stringType = "steel";
    }

    public Guitar(String type, String stringType) {
        super("guitar");
        this.type = type;
        this.stringType = stringType;
    }

    public void strum() {
        for (int i = 0; i < 6; i++) {
            super.play(); // *use super.methodName() to call a superclass method*
        }
    }

    @Override
    public String toString() {
        return stringType + "-string " + type + " guitar";
    }
}

<aside> 💡 Note: Getters and setters were omitted from the implementation above for simplicity.

</aside>

As you may have noticed, to call a superclass constructor, you use super(list of parameters). The default superclass constructor (super()) is called implicitly (by default) for any subclass’s constructor. However, if you want to use a superclass constructor with 1 or more arguments, you must do so explicitly (you have to write it out in code).