正如我使用源代码的 JDK 版本中所见,
Function.identity()
的定义如下:
static <T> Function<T, T> identity() {
return t -> t;
}
对我来说,旧的 Java 7 和旧版本背景及其内部类可以捕获太多内容,看起来每次调用
identity
函数时,Function.identity()
函数中的 lambda 都是实例化。我想知道如果函数返回强制转换字段有什么区别?
例如,我有两个类以上述两种方式定义 lambda。
final class DynamicLambda {
private DynamicLambda() {
throw new AssertionError();
}
static Function<Object, Object> identity() {
return o -> o;
}
}
final class StaticLambda {
private StaticLambda() {
throw new AssertionError();
}
static final Function<Object, Object> identity = o -> o;
}
使用
javap
和 -p
选项时,它们的 -c
类会像这样被反汇编:
Compiled from "DynamicLambda.java"
final class DynamicLambda {
private DynamicLambda();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: new #7 // class java/lang/AssertionError
7: dup
8: invokespecial #9 // Method java/lang/AssertionError."<init>":()V
11: athrow
static java.util.function.Function<java.lang.Object, java.lang.Object> identity();
Code:
0: invokedynamic #10, 0 // InvokeDynamic #0:apply:()Ljava/util/function/Function;
5: areturn
private static java.lang.Object lambda$identity$0(java.lang.Object);
Code:
0: aload_0
1: areturn
}
Compiled from "StaticLambda.java"
final class StaticLambda {
static final java.util.function.Function<java.lang.Object, java.lang.Object> identity;
private StaticLambda();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: new #7 // class java/lang/AssertionError
7: dup
8: invokespecial #9 // Method java/lang/AssertionError."<init>":()V
11: athrow
private static java.lang.Object lambda$static$0(java.lang.Object);
Code:
0: aload_0
1: areturn
static {};
Code:
0: invokedynamic #10, 0 // InvokeDynamic #0:apply:()Ljava/util/function/Function;
5: putstatic #14 // Field identity:Ljava/util/function/Function;
8: return
}
唯一的字节码差异我看到是,
invokedynamic
被调用的次数与调用DynamicLambda.identity()
的次数相同,或者在其静态初始化程序中为StaticLambda.identity
调用一次。
从语义角度来看,“动态”方法的优点是 lambda 表达式类型推断,因为“静态”方法需要未经检查的类型转换。从调用站点的角度来看,唯一的区别是用于获取恒等函数的指令:
invokestatic
用于“动态”方法,getstatic
用于“静态”方法。
这两者之间的真正区别是什么?
Function.identity()
是这样实现的吗?它们如何影响内存占用以及可能的性能?
Function.identity()
每次都返回相同的实例。
所以唯一的区别是它会根据调用者所需的类型进行调整。这给了我们想要的类型安全,