07. Java Inheritance (Part 1)

InheritanceIn Java, you may create subclasses that reuse and extend another class, so that the subclass inherits (has direct access to) certain members (variables & methods) of its superclass. (A Java subclass is like a C++ derived class).

Why is inheritance useful? The design of a program is better when you create classes for more general features, and subclasses for more detailed features. We'll see some examples of this later.

What's different about subclasses from a regular class?

    • when an object of a subclass is instantiated, all of the instance variables in the superclass (and its superclass, etc.) are allocated memory along with the subclass' instance variables
    • non-private* methods in its superclass (and its superclass, etc.) may be called on a subclass object, as well as the subclass' (non-private) methods
    • when inside a subclass instance method, the superclass (non-private) methods may be called (if the superclass method is not overriden in the subclass)
    • when inside a subclass instance method, the superclass (non-private) variables may be directly accessed (unless the subclass has a variable with the same name)

Differences from C++:

    • Java does NOT support multiple inheritance, i.e., each class may only haveone superclass (unlike C++).
    • Java allows implementing more than one interface (see p. 16).
    • Every Java class may be subclassed unless it is declared as final.
    • The default superclass for all classes isjava.lang.Object (details later)

*Non-private methods include public, protected or no access specifier (protected superclass members are accessible by methods of a subclass in the same or different package and non-subclasses in the same package)

Defining a Subclass

In the class heading, add the extends class: class subclass-id extends superclass-id

Optional: You may define the class as public

Examples:
public class SuperClass{
  int packageVar;
  public int publicVar;
  private int privateVar;
  protected int protectedVar;
} // end class SuperClass
public class SubClass1 extends SuperClass{
  void someMethod(){
     packageVar = 0; // OK if in same package
     publicVar = 0; // OK
     privateVar = 0; // Error
     protectedVar = 0; // OK
  }
} // end class SubClass1
// In another package:
public class SubClass2 extends SuperClass{
void someMethod(){
     packageVar = 0; // Error
     publicVar = 0; // OK
     privateVar = 0; // Error
     protectedVar = 0; // OK
  }
} // end class SubClass
public class Main{
  public static void main( String [] args ){
       SubClass1 sub1 = new SubClass1();
       sub1.packageVar = 0; // Error
       sub1.publicVar = 0; // OK
       sub1.privateVar = 0; // Error
       sub1.protectedVar = 0; // Error
       SubClass2 sub2 = new SubClass2();
       sub2.packageVar = 0; // Error
       sub2.publicVar = 0; // OK
       sub2.privateVar = 0; // Error
       sub2.protectedVar = 0; // Error
  } // end main
} // end class Main

NOTE: When no access specifier is given for a class, method or variable, then it can only be accessed by all methods in the same package.

More on Subclasses

Inside a Subclass:

  • In the subclass' constructor(s) you may call a superclass constructor just by doing (must be thefirst statement in the subclass' constructor): super( parameters);
  • NOTE: If you DON'T explicitly call the superclass constructor, then the JVM will try to call its default constructor (which may not exist)!
  • You may call a superclass non-private method if no method in the subclass has the same name by calling as if it’s in the same class
  • You may override a superclass method in the subclass (defining it with the exact same name and same parameters)-- this triggers polymorphism(read more about polymorphism HERE)
  • If the superclass has the same name method as in the subclass, to call it, do: super.method-id(parameters)
  • You may assign a subclass object (reference) to a superclass object variable
  • When a subclass constructor passes a parameter up to the superclass constructor via the superkeyword, the parameter cannot be a class-scope instance variable of the subclass because the subclass hasn't been constructed yet. Example extending the Grandparent class on next page:

public class BadParent extends Grandparent{

private int data=1;

public BadParent(){

super(data); // Error: can't pass data

}

} // end class BadParent

Example of Using Inheritance

public class Grandparent{
protected int data;
public Grandparent(int i){
       data=i;
} // end Grandparent constructor
public void display(){
       System.out.println("Grandparent display "+data);
} // end display method
} // end Grandparent class

public class Parent extends Grandparent{

protected int data; // different from Grandparent's
public Parent( int i ){
       super( i+1 ); // calls Grandparent constructor
       data=i;
} // end Parent constructor
public void display(){
       System.out.println("Parent display "+data);
} // end display method
} //end Parent class

public class Child extends Parent{

protected int data; // different from Parent's
public Child( int i ){
       super( i+1 ); // calls Parent constructor
       data = i;
} // end Child constructor
public void display(){
       System.out.println("Child display" + this.data);
       System.out.println("Parent data = " + 
           super.data);
       System.out.println("Grandparent data= " + 
                    ((Grandparent)this).data );
       super.display();
       // Note: Can't call Grandparent's display()
       //      from here even with casting
} // end display method
} // end Child class
Note:  (Grandparent) in the above example is casting the Child reference to its Grandparent.
In another class and file:
public class TryInheritance
{
public static void main( String[] args )
{
       Grandparent g = new Grandparent( 100 );
       Parent p1 = new Parent( 10 );
       Parent p2;
       Child c1 = new Child( 1 );
       Child c2;
       p2 = c1; // example of assigning a subclass obj. to superclass var.
       
       if( p2 instanceof Child )//always check
           c2 = (Child) p2; 
//NOTE: if you downcast and it isn't an instance,
//        an exception will be thrown
       g.display();// displays "Grandparent display 100"
       p1.display();// displays "Parent display 10"
       p2.display();// displays "Child display 1", etc.
       c1.display();// displays "Child display 1", etc.
} // end main
} // end TryInheritance