为什么使用方法引用在字节代码中生成内部类?

时间:2018-02-03 19:55:01

标签: java jvm inner-classes

我编写了使用方法引用的简单示例:

gameid, 
userid, 
betid,
score

生成的字节代码是 InnerClass

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"));
}}

我认为这个innerClass用于lambda bootstrap方法,但我不知道jvm何时创建此类的对象以及将在此类的对象中存储哪些信息。有人能解释一下吗?

1 个答案:

答案 0 :(得分:4)

这不是生成的内部类,而是JVMS §4.7.6中指定的InnerClasses属性。规范要求此属性列出不是包的成员的每个类(在常量池中引用)。

基本上,javac为它在代码中看到的所有内部类生成InnerClasses属性。 E.g。

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

        }
    }
}

上述类的字节码将Map.Entry称为Map的内部类:

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

在JDK中,lambdas使用invokedynamic指令实现。根据规范,invokedynamic的解析涉及使用以下类型的4个参数调用bootstrap方法:

  1. MethodHandle
  2. MethodHandles.Lookup
  3. String
  4. MethodType
  5. Java Runtime在内部创建这些对象,但由于字节码引用MethodHandles.Lookup类,javac会为其生成InnerClasses属性。