What actually happens in inheritance (java)? [closed]

  softwareengineering

class A {
    int a;
    int b;

    A(int i,int z) {
        a = i;
    }

    void abc() {     
        System.out.println("a is " + a);
        System.out.println("b is " + b);
    }
}
class B extends A {
    int a = 55;
    int b = 66;

    B() {
        super(14,13);
        super.b = 99;
    }
}
public class test {    
    public static void main(String[] argue) {
          B obj = new B();
          obj.abc();
    }
}

output:

a is 14
b is 99

I would refer to the above code for my questions. I don’t have some basic OOP concepts vivid. Please clear my doubts regarding the following queries:

  1. What actually happened when class B extended A? Was the code from A copied pasted in B, each variable defined in A is now defined in B also and each method definition in A is now also in B?
  2. As a class is just a template it lists the attributes that the object will have and the memory will only be allocated for each variable definition in a class when its object is made. Now if you say that when class B extended A the code from class A was not copied pasted into B i.e. the variables (int a, int b) originally defined in A their definitions are not pasted in class B.When the object of class B is created it allocates memory for variables ‘a’ and ‘b’ in class B, not of class A as their definition is not copied pasted in B. How can class B use the super class variables ‘a’ and ‘b’ even though the super class wasn’t instantiated i.e. ‘a’ and ‘b’ don’t exist in memory as class just defines a template. Does the compiler allocate separate memory portion for ‘a’ and ‘b’ on special consideration for class B as it extended class A? What about the method defined in the class A?
  3. I was expecting obj.abc() (the last statement in the main method) to print:

    a is 55
    b is 66
    

    as the method abc() was originally defined in class A and now class B inherits A so it inherited abc(). So if I called abc() with a reference of class B’s object it should have printed the values of ‘a’ and ‘b’ in class B i.e.

     a is 55
     b is 66
    

6

The output you describe does not correspond to the code you posted. It actually prints

a is 14
b is 99

I’ll get to why that’s happening later. But first, I’ll rewrite your code into a form that demonstrates the relationships typically found in inheritance:

public class A {
    int a;
    int b;

    A(int i, int z) {
        a = i;
        b = z;
    }

    void abc() {
        System.out.println("a is " + a);
        System.out.println("b is " + b);
    }
}

public class B extends A {
    B() {
        super(14, 13);
    }
}

public static void main(String[] argv) throws Exception {
    B obj = new B();
    obj.abc();
}

Which gives the output

a is 14
b is 13

This is inheritance in its simplest form, and has the following characteristics:

  • An instance of B contains two member variables, a and b. These variables are defined by class A.
  • When you invoke the method abc() on an instance of B, the JRE determines that the method is actually defined in class A. This is known as dynamic dispatch, and is one of the key features of inheritance.

Now a modification:

public class B extends A {
    B() {
        super(14, 13);
    }

    @Override
    void abc() {
        System.out.println("b is " + b);
        System.out.println("a is " + a);
    }
}

Here I’ve overridden the method abc() in class B. When the JVM examines the class, it determines that B has defined the method, so invokes that implementation and does not look for an implementation in A.

Because B extends A, and the member variables a and b are not declared private by A, B has access to those variables. The output is:

b is 13
a is 14

Another modification:

public class B extends A {
    B() {
        super(14, 13);
        super.b = 99;
    }

    @Override
    void abc() {
        System.out.println("b is " + b);
        System.out.println("a is " + a);
    }
}

This highlights the construction chain. In an inheritance hierarchy, a class’ constructor must call a superclass’ constructor. So here, B() explicitly calls A(int,int), which implicitly calls Object().

The ordering is important: immediately after the call super(14,13), the value of member variable b is 13. However, the B() constructor changes that value, so the program prints

b is 99
a is 14

I left the assignment as super.b = 99, but in this case it could also have been just been b = 99, because class B has access to the variable defined by A. However, this form becomes important in the next revision.

Let’s bring this program one step closer to your original:

public class B extends A {

    int a = 55;
    int b = 72;

    B() {
        super(14, 13);
        super.b = 99;
    }

    @Override
    void abc() {
        System.out.println("b is " + b);
        System.out.println("a is " + a);
    }
}

In this case I’m redefining the variables a and b within class B. These definitions shadow the definitions from class A. This is where it gets tricky — and why, in production code, shadowing is a code smell.

  • There are now four variables in the class instance. Two are defined by class A, and two are defined by class B.
  • The code in class B will ignore the variables defined by A
  • Unless you explicitly prefix the variable reference with super

So, after construction, here are the four variables:

  • a, defined by A, with the value 14
  • b, defined by A, with the value 99
  • a, defined by B, with the value 55
  • b, defined by B, with the value 72

Note that the variable b defined by A was explicitly changed by B‘s constructor, after it was assigned by A‘s constructor, because B‘s constructor referred to it with super.

However, the definition of method abc() in B doesn’t prefix those variables with super, so it will print the values of the variables defined by B:

b is 72
a is 55

Last step: I remove the definition of function abc() from class B.

public class B extends A {

    int a = 55;
    int b = 72;

    B() {
        super(14, 13);
        super.b = 99;
    }
}

Now the JRE again invokes the function defined in A. However, this implementation only has access to the two variables that are also defined by A; it has no knowledge of the two variables defined by B even though they exist within the object instance. So the output is

a is 14
b is 99

Why isn’t b 13? Because the constructor for B explicitly referenced the variable defined by A.

Anyone who feels the need to add references to specs should feel free to do so; I don’t think they’re necessary.

1

LEAVE A COMMENT