Java 8 Lambda 表达式编译到什么位置?

2022-09-01 19:28:23

请考虑以下 Java 8 代码段。

public static void main(String[] args) {            
   List<Integer> integers = Arrays.asList(1, 2, 3, 4, 5);

   Consumer<Integer>  consumer = x -> System.out.print(x);  

   integers.forEach(consumer);
}

编译成什么?Consumer<Integer> consumer = x -> System.out.print(x)

我知道Lambdas不是作为匿名内部类实现的。然而,接口因此必须生成某种对象,但不清楚正在生成哪种对象。Consumer<Integer>x -> System.out.print(x)

Java 8 中是否有某种新类型的对象来表示 lambda 表达式?

更新下面是该程序与 eclipse java 8 编译器一起编译的反编译程序,下面的输出是当您打开类文件时的 eclipse。

看起来 lambda 表达式正在变成包含 lambda 表达式的类上的静态方法。private static synthetic void lambda$0(java.lang.Integer x);

// Compiled from Example.java (version 1.8 : 52.0, super bit)
public class Example {

  // Method descriptor #6 ()V
  // Stack: 1, Locals: 1
  public Example();
    0  aload_0 [this]
    1  invokespecial java.lang.Object() [8]
    4  return
      Line numbers:
        [pc: 0, line: 7]
      Local variable table:
        [pc: 0, pc: 5] local: this index: 0 type: Example

  // Method descriptor #15 ([Ljava/lang/String;)V
  // Stack: 4, Locals: 3
  public static void main(java.lang.String[] args);
     0  iconst_5
     1  anewarray java.lang.Integer [16]
     4  dup
     5  iconst_0
     6  iconst_1
     7  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    10  aastore
    11  dup
    12  iconst_1
    13  iconst_2
    14  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    17  aastore
    18  dup
    19  iconst_2
    20  iconst_3
    21  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    24  aastore
    25  dup
    26  iconst_3
    27  iconst_4
    28  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    31  aastore
    32  dup
    33  iconst_4
    34  iconst_5
    35  invokestatic java.lang.Integer.valueOf(int) : java.lang.Integer [18]
    38  aastore
    39  invokestatic java.util.Arrays.asList(java.lang.Object[]) : java.util.List [22]
    42  astore_1 [integers]
    43  invokedynamic 0 accept() : java.util.function.Consumer [31]
    48  astore_2 [consumer]
    49  getstatic java.lang.System.out : java.io.PrintStream [32]
    52  aload_2 [consumer]
    53  invokevirtual java.lang.Object.getClass() : java.lang.Class [38]
    56  invokevirtual java.lang.Class.getCanonicalName() : java.lang.String [42]
    59  invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]
    62  getstatic java.lang.System.out : java.io.PrintStream [32]
    65  aload_2 [consumer]
    66  invokevirtual java.lang.Object.getClass() : java.lang.Class [38]
    69  invokevirtual java.lang.Class.getTypeName() : java.lang.String [54]
    72  invokevirtual java.io.PrintStream.println(java.lang.String) : void [48]
    75  aload_1 [integers]
    76  aload_2 [consumer]
    77  invokeinterface java.util.List.forEach(java.util.function.Consumer) : void [57] [nargs: 2]
    82  return
      Line numbers:
        [pc: 0, line: 10]
        [pc: 43, line: 12]
        [pc: 49, line: 14]
        [pc: 62, line: 15]
        [pc: 75, line: 17]
        [pc: 82, line: 18]
      Local variable table:
        [pc: 0, pc: 83] local: args index: 0 type: java.lang.String[]
        [pc: 43, pc: 83] local: integers index: 1 type: java.util.List
        [pc: 49, pc: 83] local: consumer index: 2 type: java.util.function.Consumer
      Local variable type table:
        [pc: 43, pc: 83] local: integers index: 1 type: java.util.List<java.lang.Integer>
        [pc: 49, pc: 83] local: consumer index: 2 type: java.util.function.Consumer<java.lang.Integer>

  // Method descriptor #73 (Ljava/lang/Integer;)V
  // Stack: 2, Locals: 1
  private static synthetic void lambda$0(java.lang.Integer x);
    0  getstatic java.lang.System.out : java.io.PrintStream [32]
    3  aload_0 [x]
    4  invokevirtual java.io.PrintStream.print(java.lang.Object) : void [74]
    7  return
      Line numbers:
        [pc: 0, line: 12]
      Local variable table:
        [pc: 0, pc: 8] local: x index: 0 type: java.lang.Integer

  Inner classes:
    [inner class info: #96 java/lang/invoke/MethodHandles$Lookup, outer class info: #98 java/lang/invoke/MethodHandles
     inner name: #100 Lookup, accessflags: 25 public static final]
Bootstrap methods:
  0 : # 89 arguments: {#90,#93,#94}
}

答案 1

Java 8 语言规范的当前草案指出(第 15.27.4 章)

lambda 表达式的值是对具有以下属性的类的实例的引用:

  • 该类实现目标函数接口,如果目标类型是交集类型,则实现交集的所有其他接口元素。
  • 该类声明一个方法,该方法重写函数接口超类型的抽象方法(以及可能重写其超接口的其他一些方法)。
  • 该方法的参数类型、返回类型和抛出类型由接口的函数类型给出。
  • 如果它是表达式,则该方法的主体具有计算 lambda 主体的效果,或者如果它是块,则具有执行 lambda 主体的效果;如果预期结果,则从方法返回该结果。
  • 该类不会重写上述接口或接口的其他方法,除了它可以重写该类的方法。Object

请注意,JLS没有说明代码应该如何编译,除了字节代码应该支持上面的规范。

因此,lambda 表达式返回的对象

x -> System.out.print(x);  

将是遵循上述规则的类的实例。

鉴于您的评论

consumer.getClass()

返回以下类

Example$$Lambda$1/1072591677

它似乎正在生成一个特定于lambda表达式的类似代理的类。

请参阅此处:


答案 2

推荐