ogp-notes

Implementation inheritance

Consider the following class Color, whose instances represent colors defined by their red, green, and blue components:

public class Color {
    public final int red, green, blue;
    public Color(int red, int green, int blue) {
        this.red = red;
        this.green = green;
        this.blue = blue;
    }
    public int getHue() { /* ... */ }
    public int getSaturation() { /* ... */ }
    public int getValue() { /* ... */ }
    @Override
    public String toString() {
        return "rgb(" + red + ", " + green + ", " + blue + ")";
    }
    @Override
    public boolean equals(Object other) {
        return
            other.getClass() == getClass() &&
            ((Color)other).red == red &&
            ((Color)other).green == green &&
            ((Color)other).blue == blue;
    }
    @Override
    public int hashCode() {
        return Objects.hash(red, green, blue);
    }
}

Often, this class is sufficient. But sometimes, we need to additionally store a transparency value. Instead of duplicating the existing functionality of Color, we can declare class TransparentColor as a subclass of Color:

public class TransparentColor extends Color {
    public final int transparency;
    public TransparentColor(int red, int green, int blue, int transparency) {
        super(red, green, blue);
        this.transparency = transparency;
    }
    @Override
    public String toString() {
        return
            "rgba(" + red + ", " + green + ", " + blue + ", " + transparency + ")";
    }
    @Override
    public boolean equals(Object other) {
        return
            super.equals(other) &&
            ((TransparentColor)other).transparency == transparency;
    }
    @Override
    public int hashCode() {
        return Objects.hash(super.hashCode(), transparency);
    }
}

Notice the following:

Fields are hidden, not overridden!

If a class D declares a field with the same name F as a field it inherits from its superclass C, the inherited field is hidden, not overridden! In that case, each object of class D has two fields named F: the one declared in class C, and the one declared in class D. When F is mentioned in class C, the field declared in class C is accessed; when F is mentioned in class D, the field declared in class D is accessed. You can access the field of class C from class D using notation super.F.