In this tutorial, we will deal with all the kinds of practical inheritance example programs in Java with explanations that are very important for interview purposes. 

If you practice these example programs then definitely, you can able to solve all questions based on chapter java inheritance in any java technical exam or interviews. So, let's start to learn.

Behavior 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" plays an important role to access instance variables. Consider a below example program.
Program source code 1:
    package inheritancePractice; public class P { // Declare an instance variable. int a=30; } public class Q extends P { // Declare an instance variable whose name is same as that of the superclass instance variable name. int a=50; } 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(); // Line 1 System.out.println(" Value of a: " +q.a); // Line 2 // 'a' of Q is called. // Declare superclass reference is equal to the child class object. P p = new Q(); // Line 3 System.out.println("Value of a: " +p.a); // Line 4 // 'a' of P is called. } }
    Output: Value of a: 50 Value of a: 30
Explanations: 
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: Variable '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 whether an instance variable is present or not in superclass. If the instance variable is present in the superclass at the runtime, it will call the instance variable of the superclass.

Behavior 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; // Overridden method. void msg(){ System.out.println("Base class method"); } } public class Childclass extends Baseclass { int x=50; int y=100; // Overriding method. void msg(){ System.out.println("Child class first method"); } void msg2(){ System.out.println("Child class second method"); } } public class MyTest extends Childclass { public static void main(String[] args) { Childclass obj = new Childclass(); // Line 1 System.out.println("Value of x: " +obj.x); // Line 2 // x of class Childclass is called. obj.msg(); // Line 3 // msg() of Childclass is called. obj.msg2(); // Line 4 // msg2() of Childclass is called. Baseclass obj2=new Childclass(); // Line 5 System.out.println("Value of x: " +obj2.x); // Line 6 // x of Baseclass is called. // System.out.println("Value of y: " +obj2.y); // Line 7 // Error because y does not exist in Baseclass. obj2.msg(); // Line 8 // msg() of Childclass is called. // obj2.msg2(); // Line 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
Explanations:
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 Childclass is called because the object is created for the Childclass (subclass). 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 obj2=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 objects. The reference variable 'obj2' 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.

6. When line 6 will be executed by JVM, variable "x" of Baseclass will be called because obj2 is the reference of Baseclass (superclass).

7. In line 7, an error will occur because variable "y" does not exist in Baseclass.
8. When obj2.msg(); will be executed, msg() of Childclass will be called because the object has been created for Childclass (subclass).


9. On the execution of obj2.msg2();, an error will occur because msg2() is a newly created method in Childclass. Therefore, we cannot access newly created method by creating the reference of super class and pointing to the object of subclass.

Let's take another example program related to this concept.
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"); } } public class Hi extends Hello { Hi() { System.out.println("Hi constructor"); } void show() { // Override the show() method. System.out.println("Hi method"); } } 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 will create, the constructor of class Hi will be called immediately. But, the super keyword present in the first line of class Hi will call its parent class Hello. 

Since the instance block is present in the parent class, Therefore, it will be executed first before the execution of parent class constructor and calls the show() method. Since the show() method has been overridden in the child class, therefore, show() method of class Hi will be called. Hence, 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 show() method of class Hi will be called. So, the output is "Hi method" because the object is created for the child class Hi.

d. After execution of complete 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 take an 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?"); } } public class Lion extends Animal { void food(int x){ System.out.println("Lions eat flesh"); } } public class LionTest extends Lion { public static void main(String[] args) { Animal a=new Lion(); // Line 1 a.food(); // Line 2 // food() method of class Animal is called. // a.food(20); // Line 3 // Compile time error. Lion l=new Lion(); // Line 4 l.food(); // Line 5 // food() method of class Lion is called. l.food(10); // Line 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'.

At the compile-time, the compiler checks the food() signature in the parent class. If the food() method is not overridden in the child class, it will call the parent class method at runtime. 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.

3. When the statement l.food(); will be executed, the food() method of class Lion will be called because the reference variable l is a type of Lion that is a subclass. The food() method of Animal class is available in Lion class through inheritance. Therefore, the output is "What kind of food do lions eat?".

4. When l.food(20); will be executed, the food(int x) method of class Lion will be called. The output is "Lions eat flesh".

Points to remember:
1. At the 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; // Overridding 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 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 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 BB is called because by default, x of class AA is available in class BB through inheritance. 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 BB is called because it is available in class BB by default. 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 BB is called because it is available by default in class BB. 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. msg3() is newly created method in class BB that cannot be called by using reference variable 'a' of superclass and pointing to the object of subclass. } }
    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 tutorial has covered almost all the types of java inheritance example programs with the explanation for the technical interview. All the programs are very important for freshers and experienced level interview. Keep in mind all the above concepts.

Please, share it on the social networking sites for your friends. 
Thanks for reading!
 Next ➤ Types of Inheritance in Java ⏪ Prev Next ⏩