2 min read

Method Overriding in Java

Method overriding is where you provide a new implementation of a method in a subclass.
Method Overriding in Java

Method Overriding

Method overriding can be used when extending a class or implementing an interface. Method overriding is where you provide a different implementation of a method in a subclass that is defined in a superclass. This is shown in the price() method in the following example:

public class PreciousMetal {

    public double price() {
        return 0;
    }
}

public class Gold extends PreciousMetal {

    @Override
    public double price() {
        return 2_011.28;
    }
}

public class Silver extends PreciousMetal {

    @Override
    public int price() {
        return 31.01;
    }
}

Each of these implementations will produce different values when the price() method is called.

System.out.println(new PreciousMetal().price());
System.out.println(new Gold().price());
System.out.println(new Silver().price());

This will produce the following output:

0
2011.28
31.01

Method overriding is not to be confused with method overloading. Method overloading is where you have the same method name with different parameter types or a different number of parameters.

Covariant Return Type

A covariant return type is a feature that allows for an overridden method to return a different type that what is defined in the superclass. A superclass method signature can have a superclass as the return type, and when a subclass overrides that method, it can provide a subclass of the superclass instead.

public class PreciousMetal {

    @Override
    public PreciousMetal copy() {
        return new PreciousMetal();
    }
}

public class Gold extends PreciousMetal {

    @Override
    public Gold copy() {
        return new Gold();
    }
}

public class Silver extends PreciousMetal {

    @Override
    public Silver copy() {
        return new Silver();
    }
}

In this example, you will notice that the copy() method in PreciousMetal has a return type of PreciousMetal. In each of the subclasses, when copy() is overridden, it returns the subclass instead of PreciousMetal.

You cannot override a method and specify a superclass instead for the return type. It has to be the same type or a subclass of that type, or it will result in a compiler error.

public class FoolsGold extends Gold {

    // Compiler Error:
    //   copy() in FoolsGold cannot override copy() in Gold
    //     return type PreciousMetal is not compatible with Gold
    @Override
    public PreciousMetal copy() {
        return new FoolsGold();
    }
}

When working with primitive types, the return type has to stay the same when overriding a method. When overriding a method that returns void, the overridden method must also return void. This feature is only supported with object types.

@Override Annotation

The @Override annotation is used when overriding a method. Marking a method with @Override, the compiler will ensure that the method is overriding a method in an interface or class. If it isn't overriding anything, it will generate a compiler error.

public class PreciousMetal {

    public double price() {
        return 0;
    }
}

public class Gold extends PreciousMetal {

    // Compiler Error:
    //   Method does not override method from its superclass
    @Override
    public void printPrice() {
        // ...
    }
}

Always use the @Override annotation when overriding methods.

Preventing Method Overriding

Sometimes you need to restrict the ability to override a method. You can prevent someone from overriding a method by marking it with the final keyword.

public class Metal {

    public final void printPrice() {
        // ...
    }
}

The printPrice() method in Metal is marked as final. If a subclass tries to override it, it will result in a compiler error.

public class Gold extends Metal {

    // Compiler Error:
    //   printPrice() in Gold cannot override printPrice() in Metal
    //     overridden method is final.
    @Override
    public void printPrice() {
    }
}

Conclusion

Overriding methods is where you override a method and provide a new implementation of that method in a subclass. It is important to use the @Override annotation so the compiler verifies that the method is actually overridden. Also, when overriding a method that returns an object, you can return a subclass instead.