Inheritance Example Programs in Java


In this tutorial, we will learn the different types of practical inheritance example program in Java with the explanation.
Java Inheritance example programs

Behaviour of Instance Variables in case of Inheritance


You know that Instance variables are initialized at compile time. When the instance variable of the superclass is same as that of the child class instance variable name, the reference type play an important role to access the instance variable. Consider a below example program.
Program source code 1:
    package inheritancePractice; public class P { // Declare an instance variable. int a=30; } package inheritancePractice; public class Q extends P { // Declare an instance variable whose name is same as that of the superclass instance variable name. int a=50; } package inheritancePractice; public class Test extends Q { public static void main(String[] args) { // Create an object of class Q and call the instance variable using reference variable q. Q q=new Q(); // (1) System.out.println(" Value of a: " +q.a); // (2) // 'a' of Q is called. // Declare superclass reference is equal to the child class object. P p=new Q(); // (3) System.out.println("Value of a: " +p.a); // (4) // 'a' of P is called. } }
    Output: Value of a: 50 Value of a: 30
Explanation: 
1. Line number 1: Inside the main() method, an object of class Q has been created. The reference variable q is pointing to the object of class Q.
2. Line number 2: Variable 'a' of Q is called because the reference variable of the class Q has been created and is pointing to the object of class Q.
3. Line number 3: The superclass reference variable is declared equal to the child class object.
4. Line number 4: 'a' of P is called because, in the main() method, the reference variable of class P has been created but the object is created for the child class whereas the object is referring itself to the superclass. As the object is referring to the superclass at compile time, the compiler checks that whether an instance variable is present or not. If the instance variable is present in the superclass, at runtime, it will call the instance variable of the superclass. (Remember this point).

Behaviour of Overriding method in case of Inheritance


Let's take one simple example program to understand the behavior of overriding methods in case of inheritance.
Program source code 2:
    package inheritancePractice; public class Baseclass { int x=20; void msg(){ System.out.println("Base class method"); } } package inheritancePractice; public class Childclass extends Baseclass { int x=50; int y=100; // Override the msg() method. void msg(){ System.out.println("Child class first method"); } void msg2(){ System.out.println("Child class second method"); } } package inheritancePractice; public class MyTest extends Childclass { public static void main(String[] args) { Childclass obj=new Childclass(); // (1) System.out.println("Value of x: " +obj.x); // (2) // x of class Childclass is called. obj.msg(); // (3) // msg() of Childclass is called. obj.msg2(); // (4) // msg2() of Childclass is called. Baseclass obj1=new Childclass(); // (5) System.out.println("Value of x: " +obj1.x); // (6) // x of Baseclass is called. // System.out.println("Value of y: " +obj1.y); // (7) // Error because y does not exist in Baseclass. obj1.msg(); // (8) // msg() of Childclass is called. // obj1.msg2(); // (9) // Error because the method msg2() does not exist in Baseclass. } }
    Output: Value of x: 50 Child class first method Child class second method Value of x: 20 Child class method
Points to remember:
1. Method overriding is only possible in the case of inheritance when the superclass method is overridden in its subclass. In the method overriding, method name, its argument type, the number of arguments, and return type must be the same.
2. Line number 2: The variable 'x' of the child class is called because the object is created for the child class. The reference variable obj is pointing to the object of the child class.

3. Line number 3: Here, msg() method of the child class is called because when any overridden method is called, it completely depends on the object through which it is called and the appropriate method call takes place according to this object. Since the object has been created for the child class, So msg() method of the child class will be called not of a parent class. 

4. Line number 5: Here, Baseclass obj1=new Childclass() implies that the superclass reference variable is declared equal to the child class object. In other words, the superclass reference variable holds the address of the created subclass. The reference variable 'obj1' is eligible to call only the members of a superclass. 
5. Line number 8: msg() method of Childclass is called. This is because the object is created for the child class. 
Let's take another program related to this.
Program source code 2:
    package inheritancePractice; public class Hello { // Declare an instance block. { show(); } Hello(){ System.out.println("Hello constructor"); show(); } void show(){ System.out.println("Hello method"); } } package inheritancePractice; public class Hi extends Hello { Hi(){ System.out.println("Hi constructor"); } void show() { // Override the show() method. System.out.println("Hi method"); } } package inheritancePractice; public class TestHelloHi extends Hi{ public static void main(String[] args) { Hi obj=new Hi(); // (1) obj.show(); // (2) // show() method of Hi class is called. // Superclass reference is equal to child class object. Hello obj1=new Hi(); //(3) obj1.show(); // (4) } }
    Output: Hi method Hello constructor Hi method Hi constructor Hi method Hi method Hello constructor Hi method Hi constructor Hi method
Explanation:
1. Line number 1: 
a. When an object of class Hi is created, It calls the constructor of class Hi. But, the class Hi has got Hello as its parent class, the constructor of class Hello will be called first. Since the instance block is present in the parent class, it will be executed first before the parent class constructor and calls the show() method. The show() method is overridden in the child class and the object is created for the child class. Therefore, the output will be "Hi method". 
b. After executing the instance block, the constructor of the parent class will be executed. The output will be "Hello constructor".
c. Inside the parent class constructor, The overridden show() method will be called. So, the output is "Hi method" because the object is created for the child class Hi.
d. After executing parent class constructor, the constructor of Hi (child class) will be called.

2. Line number 2: The show() method of class Hi is called because the object is created for the child class.
3. The output will be the same for line number 3 and 4.

Behaviour of Overloaded method in Inheritance


Method overloading is done at the compile time. Therefore, an appropriate method is invoked according to the reference type to call an overloaded method. Let's see a simple example program to clarify this. 
Program source code 3:
    package inheritancePractice; public class Animal { void food(){ System.out.println("What kind of food do lions eat?"); } } package inheritancePractice; public class Lion extends Animal { void food(int x){ System.out.println("Lions eat flesh"); } } package inheritancePractice; public class LionTest extends Lion { public static void main(String[] args) { Animal a=new Lion(); // (1) a.food(); // (2) // food() method of class Animal is called. // a.food(20); // (3) // Compile time error. Lion l=new Lion(); // (4) l.food(); // (5) // food() method of class Animal is called. l.food(10); // (6) // food() method of class lion is called. } }
    Output: What kind of food do lions eat? What kind of food do lions eat? Lions eat flesh
Explanation:
1. Line number 1 implies that 'a' is the reference of the parent class whereas an object is created for the child class. When line number 2 is executed, food() method is called through the reference type 'a' then at a compile time, the compiler checks the food() signature in the parent class. If the food() method is not overridden, at runtime it will call the parent class method. That's why the output is "What kind of food do lions eat?".
2. When line number 3 is executed, it will give compile time error. This is because the parent class Animal does not have a food method that takes an integer argument.

Points to remember:
1. At a compile time, an object reference variable plays an important role to call the method.
2. At runtime, the type of object created plays an important role to call the method.

Now consider the below scenarios.
Program source code 4: This program creates a superclass called AA and one subclass of it, called BB. Superclass AA declares two variables x, y, and two methods called msg1(), and msg2(). The subclass overrides one variable y and one method msg2() declared in AA. It also declares one variable z and one method called msg3(). 
    package inheritancePractice; public class AA { int x=20; int y=30; void msg1(){ System.out.println("I am msg1 in class AA"); } void msg2(){ System.out.println("I am msg2 in class AA"); } } package inheritancePractice; public class BB extends AA { int y=50; int z=60; // Override msg2() method. void msg2(){ System.out.println("I am msg2 in class BB"); } void msg3(){ System.out.println("I am msg3 in class BB"); } }
Only change below class for all type of below scenarios.
Scenario 1: In this scenario, there is a class Scenario1. Inside the main() method, an object of class AA is created and calls the variables and methods by using the object reference variable.
    package inheritancePractice; public class Scenario1 { public static void main(String[] args) { // Scenario 1. // Create an object of class AA. AA a=new AA(); // 'a' is reference variable of class A and pointing to the object of class AA. Therefore, superclass object reference a is eligible to call only A. System.out.println("Value of x: " +a.x); // x of class AA is called. System.out.println("Value of y: " +a.y); // y of class AA is called. // System.out.println("Value of z: " +a.z); // // Error because z does not exist in AA. // Call msg1() and msg2() methods using reference variable a. a.msg1(); // msg1 of class AA is called. a.msg2(); // msg2 of class AA is called. // a.msg3(); //Error because The method msg3 not exist in AA. } }
    Output: Value of x: 20 Value of y: 30 I am msg1 in class AA I am msg2 in class AA
Scenario 2: 
    package inheritancePractice; public class Scenario2 { public static void main(String[] args) { // Create an object of class BB. BB b=new BB(); // Here, 'b' is reference variable of class BB and pointing to the object of class BB. System.out.println("Value of x: " +b.x); // x of class AA is called. System.out.println("Value of y: " +b.y); // y of class BB is called, not of class AA because the object is created for class BB. System.out.println("Value of z: " +b.z); // z of class BB is called. b.msg1(); // msg1 of class AA is called. b.msg2(); // msg2 of class BB is called, not of class AA because an object is created for class BB. b.msg3(); } }
    Output: Value of x: 20 Value of y: 50 Value of z: 60 I am msg1 in class AA I am msg2 in class BB I am msg3 in class BB
Scenario 3:
    package inheritancePractice; public class Scenario3 { public static void main(String[] args) { // Superclass reference is equal to child class object. AA a=new BB(); // 'a' is reference variable of class AA but pointing to the object of class BB. System.out.println("Value of x: " +a.x); // x of class AA is called. System.out.println("Value of y: " +a.y); // y of class AA is called. // System.out.println("Value of z: " +a.z); //Error because z does not exist in AA. a.msg1(); // msg1 of class AA is called. a.msg2(); // The overridden msg2 of class BB is called because object is created for class BB. // a.msg3(); // Error because msg3 does not exist in AA. } }
    Output: Value of x: 20 Value of y: 30 I am msg1 in class AA I am msg2 in class BB
Scenario 4:
    package inheritancePractice; public class Scenario4 { public static void main(String[] args) { AA a=new AA(); BB b=new BB(); a=b; System.out.println("Value of x: " +a.x); System.out.println("Value of y: " +a.y); // System.out.println("Value of z: " +a.z); // Error because z does not exist in class AA. a.msg1(); a.msg2(); // a.msg3(); // Error msg3 of class AA not exist. } }
    Output: Value of x: 20 Value of y: 30 I am msg1 in class AA I am msg2 in class BB
Scenario 5:
    package inheritancePractice; public class Scenario5 { public static void main(String[] args) { BB b=new AA(); // Syntax error. // Try calling everything by using b. } }
Scenario 6:
    package inheritancePractice; public class Scenario6 { public static void main(String[] args) { AA a=new BB(); BB b=new BB(); b=(BB)a; // It looks like superclass assigned to subclass but it translates internally to // BB b=new BB(); // It is equivalent to 2nd scenario. System.out.println("Value of x: " +a.x); System.out.println("Value of y: " +a.y); // System.out.println("Value of z: " +a.z); // Error because z does not exist in class AA. a.msg1(); a.msg2(); // a.msg3(); // Compilation error. } }
    Output: Value of x: 20 Value of y: 30 I am msg1 in class AA I am msg2 in class BB
Final words: 
Hope that this article has covered the different types of practical inheritance example programs in Java with the explanation. All the programs are very important for the beginners and freshers. Keep in mind all the above concepts.
Thanks for reading!