Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the JVM consider superinterfaces when resolving non-interface methods? (JVM 5.4.3.3)

Tags:

java

jvm

The JVM spec (5.4.3.3) describes how method resolution is done for method refs. If it cannot find a method in a class or its superclasses, it tries to find the method in the superinterfaces.

What is the reason for this? Wouldn't a method declared by a superinterface be listed in the constant pool as an interface method ref instead of a method ref?

My understanding is that method refs are used in invokevirtual operations, whereas interface method refs are used in invokeinterface operations. I don't see how one could invoke an interface method using invokevirtual <methodref> .

like image 781
MattDs17 Avatar asked Apr 23 '20 18:04

MattDs17


People also ask

What is method resolution in Java?

The process of compiler trying to resolve the method call from given overloaded method definitions is called overload resolution. If the compiler can not find the exact match it looks for the closest match by using upcasts only (downcasts are never done).

What is linking resolution?

This information is basically stored in the run-time constant pool. So when the JVM starts execution, it will use those symbolic references to locate those classes and it's components in the classloader. So resolving is a process of converting these symbolic references to their actually references.

Which classes are loaded when JVM starts?

Initially when a JVM starts up, nothing is loaded into it. The class file of the program being executed is loaded first and then other classes and interfaces are loaded as they get referenced in the bytecode being executed.

What is method area in Java?

Method Area. The Java Virtual Machine has a method area that is shared among all Java Virtual Machine threads. The method area is analogous to the storage area for compiled code of a conventional language or analogous to the "text" segment in an operating system process.


1 Answers

Why not?

You can invoke .stream() on an ArrayList<> just fine. In fact, the following snippet

ArrayList<Object> arr = new ArrayList<>();
arr.stream();

will be compiled to

     0: new           #16                 // class java/util/ArrayList
     3: dup
     4: invokespecial #18                 // Method java/util/ArrayList."<init>":()V
     7: astore_1
     8: aload_1
     9: invokevirtual #19                 // Method java/util/ArrayList.stream:()Ljava/util/stream/Stream;

But ArrayList<> (or any of it's superclasses) don't have a .stream() method.
The method implementation that is used is from the interface Collection:

default Stream<E> stream() {
    return StreamSupport.stream(spliterator(), false);
}

But if, at any point, ArrayList<> decides that it can provide a better .stream() method, then you don't want to compile your code again.
Also the implementation (or non-implementation) of the .stream() method would leak through, and it's better to avoid that.

like image 97
Johannes Kuhn Avatar answered Oct 13 '22 13:10

Johannes Kuhn