Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java bytecode operation 'invokevirtual' does not keep consistency for the methods inherited by Object

I have following codes.

public class Parent {

    @Override
    public int hashCode() {
         return 0;
    }

}

public class Child extends Parent {

    public void test() {
        this.toString();
        this.hashCode();
    }

}

As you see in the above codes, Child inherits toString() from Object and hashCode() from Parent. Bytecode operation of Child#test is as following.

ALOAD 0: this
INVOKEVIRTUAL Object.toString() : String
ALOAD 0: this
INVOKEVIRTUAL Child.hashCode() : int
RETURN

I think if invokevirtual calls Object.toString(), it should call Parent.hashCode() for consistency. or, Child.hashCode() called, then Child.toString() should be called.

However, invokevirtual does not keep its consistency if and only if target method is inherited by Object.

Only that case, invokevirtual calls method in the Object. For other cases, invokevirtual calls method in current class.

I want to know why this happens.

like image 795
Hozard Avatar asked Mar 02 '13 08:03

Hozard


1 Answers

According to JVM specification p. 3.7:

The compiler does not know the internal layout of a class instance. Instead, it generates symbolic references to the methods of an instance, which are stored in the runtime constant pool. Those runtime constant pool items are resolved at runtime to determine the actual method location.

It means that all these symbolic Child.hashCode() are only constants, which are not specifying some kind of how JVM calls this methods. It seems, that for toString() method compiler knows, that this method has its base implementation in Object class, so it puts symbolic constant to Object class in constant pool - this is some kind of optimization, which makes compiler for JVM:

  Constant pool:
const #2 = Method   #24.#25;    //  java/lang/Object.toString:()Ljava/lang/String;
...
const #24 = class   #34;    //  java/lang/Object
const #25 = NameAndType #35:#36;//  toString:()Ljava/lang/String;
like image 63
Andremoniy Avatar answered Oct 12 '22 22:10

Andremoniy