Inheritance Rules

We use the following class definitions as examples to illustrate the rules.
class P {
    public P(int i) {  };
    public P() { };
    public void m() {  };
    public void m1() {  };
}

class Q extends P {
    public void m() {  };
}

class Z {
    public static void main(String[] args) {
       P p1 = new P();
       P p2 = new Q(); 
       Q q1 = new Q(); 

    }
}
Note: In a class hierarchy, subclasses are written BELOW the classes they extend.
Remember that a variable is an instance of type X if it was created using a constructor of type X.
  1. When an instance method is called, Java looks for the method most closely associated with the type of that instance.This is independent of the type of the variable referencing the instance.

    For example, if the following code is inserted at the end of the main method in class Z, then the comments following each method call explain exactly which method is called.

           p1.m();  // calls m() defined in class P
           p2.m();  // calls m() defined in class Q
           q1.m();  // calls m() defined in class Q
    
  2. A variable of type X can be assigned (i.e., X x=expression) either an expression of type X or an expression whose type is a subclass of X. Another way to say this is that the type of the right-hand side of an assignment statement must be the same as or a subclass of the type of the left hand side of the statement.
    Note:This type check is done at compile time.

    For example, P p2 = new Q(); is a legal assignment statement because Q is a subclass of P.

  3. You can only cast a variable of type X to type Y if either X and Y are the same or one is the subclass of the other. For example, if we had the following class R:
    class R extends P {
        public void m() {  };
    }
    
    And R r = new R(); we cannot say q1 = (Q)r; because R is neither the same as Q nor a subclass of Q.
    Note:This type check is done at compile time.

  4. You only cast an instance of type Y to type X if either: X and Y are the same or Y is a subclass of X. If Y is not the same as X nor a subclass of X then an instance of type Y does not have an X part.

    For example, Q q2 = (Q)p2;, follows this rule because p2 was created as an instance of type Q, and q2 is of type Q. Another statement that follows this rule is p1 = (Q)p2;

    Note:This type check is done at runtime. It depends on the type of the particular instance being cast when the code is executed.

    For example, q1 = (Q)p1; will compile okay because the variable p1 is of type P which can be cast to Q. But when we try to run this statement, java notices that p1 refers to an instance of type P. Since P is not the same as Q or a subclass of Q, it gives a "ClassCastException" error.

    Also note the difference between this rule and the previous rule. The statements P r = new R(); q1 = (Q)r; will compile because the variables have types that follow rule 3, but we will get a runtime error because the instance of the object referred to by r does not follow this rule.

    There is a diagram to help you understand rules 3 and 4.

  5. If x1 is a variable of type X, then the method call x1.m() is allowed only if m is a method of class X (this includes methods inherited from the superclasses of X).
    Note:This check is done at compile time.

  6. For example, q1.m1(); follows this rule.

  7. The first statement of a constructor for Y may call a constructor for its superclass X. This has the effect of initializing the X part of the new instance. Use the syntax: super(constructor arguments)

    For example, we can define the following constructor for Q:

        public Q(int j) {
            super(j);  // calls the constructor in P
        }
    
  8. To call a method "m" in the superclass, use the syntax: super.m(arguments). For example, super.m1() may be called from within a method in class Q.

  9. To refer to an instance variable v in the current class, you can use the syntax: this.v

  10. As part of the initialization of an instance, java automatically calls the constructor for the superclass of the instance (unless an explicit call to a superclass constructor is supplied as in rule 6).

    For example, the following constructor for Q calls the constructor P().

        public Q(int a) {
           // calls the constructor P();
           System.out.println(a);
        }
    

    Note: Java will automatically supply a default no-argument constructor for you if you don't define a constructor for your class.