2

I am reading a Java text book and came across a doubt. A reference variable of a superclass can be assigned a reference to an object of any subclass derived from that superclass. However, when a reference to a subclass object is assigned to a superclass reference variable, you will have access only to those parts of the object defined by the superclass. Example:

class X {
    int a;
    X(int i) {
        a = i; 
    }
}

class Y extends X {
    int b;
    Y(int i, int j) {
        super(j);
        b = i;
    }
}

class SupSubRef {
    public static void main(String args[]) {
        X x = new X(10);
        X x2;
        Y y = new Y(5, 6);
        x2 = x; // OK, both of same type
        System.out.println("x2.a: " + x2.a);
        x2 = y; // still Ok because Y is derived from X
        System.out.println("x2.a: " + x2.a);
        // X references know only about X members
        x2.a = 19; // OK
        // x2.b = 27; // Error, X doesn't have a b member
    }
}

So, in the above example, x2 (a variable of the superclass type) can refer to an object of the derived class, bit it cannot access subclass specific members. However, in the discussion on method overriding, it is shown that a superclass reference variable's call to an overridden method can be resolved to the subclass method. But the subclass method is not defined in the superclass, so isn't this a contradiction, how is the superclass reference variable able to access the subclass specific method? Example:

class Sup {
    void who() {
        System.out.println("who() in Sup");
    }
}
class Sub1 extends Sup {
    void who() {
        System.out.println("who() in Sub1");
    }
}
class Sub2 extends Sup {
     void who() {
         System.out.println("who() in Sub2");
     }
}

class DynDispDemo {
    public static void main(String args[]) {
        Sup superOb = new Sup();
        Sub1 subOb1 = new Sub1();
        Sub2 subOb2 = new Sub2();
        Sup supRef;
        supRef = superOb;
        supRef.who();
        supRef = subOb1;
        supRef.who();
        supRef = subOb2;
        supRef.who();
    }
}

The output from the program is shown here:

who() in Sup
who() in Sub1
who() in Sub2

So how is supRef able to access the who method in the subclass object?

racerX
  • 930
  • 9
  • 25
  • 1
    This is called polymorphism and it's the abc of object oriented programming, continue reading your book, it will be explained. – Oleg Dec 20 '17 at 01:30
  • Hi, I did read the book but was not any clearer. Could you please see my comment in the below answer and see if my understanding is right? – racerX Dec 28 '17 at 21:31
  • 1
    Yes, it's right. See also the following answer for a clear explanation https://stackoverflow.com/a/6308235/1398418 – Oleg Dec 28 '17 at 22:16

1 Answers1

3

When the textbook says that you can't access subclass-specific members with x2, it meant that you can't access them at compile time.

To the compiler. x2 is of type X (though it's really of type Y at runtime), so when the compiler sees you trying to access stuff defined in Y, it spots and says "that is not defined in X. You can't do that!"

However, we all know that at runtime, x2 stores a reference to a Y object. At runtime, you can indeed access members defined in Y with x2. You can prove this by using reflection.

At runtime, x2 is of type Y, so obviously Y's implementation will be called.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • Hi thanks, I understand that at runtime x2 points to a Y object (type of x2 is still X), so at runtime x2 can access any Y member, whether overridden or not. But during compilation phase, we can only access overridden methods (at compile phase compiler treats x2 as type X and only overridden methods are accessible) and not other members since they are not defined in the X. So, although x2 points to Y object and at runtime could access any Y member, only overridden methods are accessible at compile time. Thus practically we cannot access non overridden methods/data members in Y. Am I correct? – racerX Dec 28 '17 at 21:29
  • 1
    @racerX I would say that you are mostly right. The compiler does not actually know that a method is overridden. You are able to call Sub2.who at compile time because there is a `who` in Sup, not because it is overridden. The subclass implementation is called at runtime *because it is overridden*. – Sweeper Dec 28 '17 at 23:48