1

How does inheritance work (in Java) when casting is involved? Casting works as expected with instance variables but not with methods.

Given the following code; the comments in class C refers to the resolutions done by the compiler as can be inspected by looking into the bytecode.

class A {
    String name;
    void test1() {
        System.out.println("ATest1 =" + this);
    }
    void test2() {
        System.out.println("ATest2 =" + this);
    }
}

class B extends A {
    String name;
    void test1() {
        System.out.println("BTest1 =" + this);
    }
    void test3() {
        System.out.println("BTest3 =" + this);
    }
}

class C {
    static public void main(String... args) {
        B b = new B();
        b.name = "Peter";      // Field B.name
        ((A)b).name = "Petra"; // Field A.name
        System.out.println(b.name);
        System.out.println(((A)b).name);
        b.test1();             // Method B.test1(b)
        ((A)b).test1();        // Method A.test1(b)
        b.test3();             // Method B.test3(b)
        b.test2();             // Method B.test2(b)
    }
}

You might use casting to set name in instance b and to set name in its accompanying "virtual" object, an instance of class A, so to speak.

However, if methods are involved the call always resolves to instance b calling test1 in class B. This is despite the fact that in ((A)b).test1() method A.test1(b) (from a JVM viewpoint) is called.

I don't get the semantics. Can you help?

My guess is that ((A)b).test1() confirms existence of method test1 in class A. Nonetheless, class B is the starting point for method resolution when it comes to invoking the method, because of ((A)b).getClass() ==> class B. But why is casting "ignored"? Do you have any pointers to the Java Language Specification? I don't know where to look for.

denkspuren
  • 11
  • 4
  • You're probably confused by having two variables named `name`. You _should_ delete `String name;` from class `B`, after which you will get the correct behavior. In any event, casting is "supposed to be" ignored -- that's the entire point of method overriding. – Louis Wasserman Jan 06 '21 at 19:04
  • 1
    There is no inheritence or overrides of fields like `name` in Java. Those are two different variables, which share the same name. In Java speak, for class `B` you can access the variable using `super`, eg. `super.name=Petra` and `this.name=Peter`. – Thomas Jungblut Jan 06 '21 at 19:05
  • You have got *two* instance variables (fields) both named `name`. You have got only *one* method called `test1`. he same method is overridden in class `B`. So no matter if you cast or not, the same method is called. Read up in how virtual methods are called (methods in Java are virtual). – Ole V.V. Jan 06 '21 at 19:30
  • Obviously I'm not the first one asking this question; thanks a lot for the references. But the answers are not so specific as I was hoping for. Looking into the Bytecode unveiled that casting is resolved as expected. Looks like that [invokevirtual](https://stackoverflow.com/questions/65552062/implementation-of-invokevirtual-in-jvm) is responsible for the somewhat unexpected behavior; I need to look into that. – denkspuren Jan 06 '21 at 21:52
  • 1
    The JVM specification for [invokevirtual](https://docs.oracle.com/javase/specs/jvms/se15/html/jvms-6.html#jvms-6.5.invokevirtual) says in 3rd paragraph under "Description" that the method is selected with respect to the class of the argument to invokevirtual, in my example class `B` of instance `b`. The casting in `((A)b).test1()` requires the method `test1()` to exist at compilation time, but it is not chosen at runtime. That's what irritated me. Thanks for your support. – denkspuren Jan 06 '21 at 22:31
  • I sounds like you understand now. Thanks for reporting back. Feel free to ask a new question about anything that may still not be clear. – Ole V.V. Jan 07 '21 at 10:15

0 Answers0