lolcio
lolcio

Reputation: 352

Why does using a method reference generate an inner class in byte code?

I wrote simple example of using method reference:

public class Main {
private static String identity(String param) {
    return param;
}

public static void main(String... args) {
    Function<String, String> fun = Main::identity;
    System.out.println(fun.apply("Hello"));
}}

And in generated byte code is InnerClass:

InnerClasses:
 public static final #68= #67 of #71; //Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
BootstrapMethods:
0: #35 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
Method arguments:
  #36 (Ljava/lang/Object;)Ljava/lang/Object;....

I supposed this innerClass is used in lambda bootstrap method, but I do not know when jvm create object of this class and what information will be store in object of this class. Could anyone explain it to me?

Upvotes: 5

Views: 414

Answers (1)

apangin
apangin

Reputation: 98550

This is not a generated inner class, but rather InnerClasses attribute specified in JVMS §4.7.6. The specification requires that this attribute lists every class (referenced in the constant pool) that is not a member of a package.

Basically, javac generates InnerClasses attribute for all inner classes it sees in the code. E.g.

public class Test {
    public static void main(String[] args) {
        for (Map.Entry e : Collections.emptyMap().entrySet()) {

        }
    }
}

The bytecode for above class will refer to Map.Entry as an inner class of Map:

InnerClasses:
   public static #31= #7 of #23; //Entry=class java/util/Map$Entry of class java/util/Map

In JDK lambdas are implemented with invokedynamic instruction. According to the specification, resolution of invokedynamic involves calling a bootstrap method with 4 arguments of the following types:

  1. MethodHandle
  2. MethodHandles.Lookup
  3. String
  4. MethodType

Java Runtime creates these objects internally, but since the bytecode refers to MethodHandles.Lookup class, javac generates InnerClasses attribute for it.

Upvotes: 8

Related Questions