面试八股文套路 (面试题八股文啥意思)

背景

Java 8引入了Lambda表达式,那么在Java 8中到底是如何实现Lambda表达式的呢? Lambda表达式经过编译之后,到底会生成什么东西呢?

在JAVA的世界中,万物皆对象,而对象模型是class(类),所以自然Lambda表达式最终也要通过类来表达。

实现

定义一个类实现Lambda表达式的接口, 并实现对应的方法,方法中完成具体的代码逻辑,在调用的地方,new出该类的对象并调用接口方法。(一般类,内部类,匿名内部类)

import java.util.function.Consumer;

public class Lambda1 {
    public static void main(String[] args) {
        Consumer c = s -> System.out.println(s);
        c.accept("hello lambda");
    }
}

对应生成类:

static class PrintExample implements Consumer {

    @Override
    public void accept(Object o) {
        System.out.println(o);
    }
}
    public static void main(String[] args) {
        new PrintExample().accept("hello lambda");
    }

可以看到如上实现,最终效果是一致的。

JDK实现

那JDK的实现是如何的呢,为了探究Lambda表达式是如何实现的,就得需要研究Lambda表过式最终转化成的字节码文件

javap -p Lambda1. class

JDK生成的代码,多出一个私有静态方法private static void lambda$main$0

public class Lambda1 {
  public Lambda1();
  public static void main(java.lang.String[]);
  private static void lambda$main$0(java.lang.Object);
}

这个私有的静态函数干的就是Lambda表达式里面的内容,那在Consumer的accept里是如何调到lambda$main$0呢?

通过断点,可以看到:

面试八股什么意思,面试八股文套路

JDK 生成了一个另外一个类 Lambda1$Lambda$1,进入accept

此处生成的类名规则为:

类名格式如 <包名>.<类名>$Lambda$/.

number是由一个计数器生成counter.incrementAndGet()。

后缀/中的数字是一个hash值, 那就是类对象的hash值c.getClass().hashCode(),在Klass::external_name()中生成。

面试八股什么意思,面试八股文套路

在accept里调用了上面生成的私有静态方法。

增加命令行,可以将中间生成的类Lambda1$Lambda$1输出

-Djdk.internal.lambda.dumpProxyClasses

生成的类反编译后如下

import java.lang.invoke.LambdaForm.Hidden;
import java.util.function.Consumer;

// $FF: synthetic class
final class Lambda1$Lambda$1 implements Consumer {
    private Lambda1$Lambda$1() {
    }

    @Hidden
    public void accept(Object var1) {
        Lambda1.lambda$main$0(var1);
    }
}

至此λ表达式的JDK实现原理,真想大白。

总结

JDK针对λ的实现,生成一个私有的静态方法(方法体里即具体执行逻辑)并生成的一个实现接口的类,并在回调里调用私有的静态方法。