Inheritance

Overriding

  • cannot override static methods
    • because overriding is based on dynamic binding at runtime but static methods are bound at compile time
  • overloaded methods in child class neither overrides nor hides, they are unique to subclass

Access Modifier

  • access specifier of overridden method (parent class) access specifier of overriding method (child class)
  • private < package-private < protected < public
  • access_modifiers
  • protected instance method in the superclass can only be made in child class as:
    • protected 
    • public

Non-access modifier

  • Assuming it is allowed to override, the following keywords can be allowed??:
    • final
    • synchronized
    • native
  • final cannot be overridden, but can be applied to non-final overridden methods
  • static cannot be non-static and vice versa in overridden methods
  • compile-time error if you attempt to change:
    • instance method in the superclass —X static method in the subclass
    • and vice versa

throws keyword

class A {
    protected String foo() throws Exception{
        return "a";
    }
}
 
class B extends A {
    // protected --> public (more access)
    // Exception --> IOException (less broad)
    // throws clause can be omitted completely
    @Override
    public String foo() throws IOException {
        return "b";
    }
}

Multiple Inheritance with interfaces

  • Multiple inheritance is achieved by default interface methods since they are inherited and provide implementation
  • static methods in interfaces are never inherited
    • Hence you should call them by their parent interface name directly
  • Inheritance rules:
    • Instance methods are preferred over interface default methods
    // Horse, Flyer and Mythical all have implementation for identifyMyself()
    // Horse method will be preferred (no overriding)
    class Pegasus extends Horse implements Flyer, Mythical {}
    • Methods that are already overridden by other candidates are ignored. This circumstance can arise when super types share a common ancestor.
    // has default method: identifyMyself()
    interface Animal {}
    // has default method: identifyMyself()
    interface EggLayer extends Animal {}
    // does not define any method, takes identifyMyself() from Animal
    interface FireBreather extends Animal {}
     
    // will take EggLayer implementation
    class Dragon implements EggLayer, FireBreather {}
  • If two or more independently defined default methods conflict, or a default method conflicts with an abstract method, then the Java compiler produces a compiler error
  • See Diamond problem
public interface OperateCar {
    default public int startEngine(EncryptedKey key) { /*implementation*/ }
}
 
public interface FlyCar {
    default public int startEngine(EncryptedKey key) { /*implementation*/ }
}
 
// must define startEngine() since there is a clash
public class FlyingCar implements OperateCar, FlyCar { }

Hiding vs overriding