Java 中分配给功能接口的对象是什么?
What is the object assigned to a Functional Interface in Java?
我是 Java 中的 Lambda 表达式的新手,所以如果这个问题看起来很愚蠢,请不要反应太过苛刻: 实现的实际对象是什么我把它分配给一个FunctionalInterface
?即,如果我执行 List<String> lst = new ArrayList<>()
,我将实现一个 ArrayList
对象。如果我这样做 Function<String,String> fct = s -> s
,创建的对象是什么?该对象是不可变的吗,即 public static final Function<String,String> REUSE_OFTEN = s -> String.valueOf(s)
?
有意义吗?
当您编写 lambda 表达式时 -
Function<String,String> fct = s -> s;
它只是创建了一个匿名的 class,实现了 Function<String, String>
接口,并用 s -> s
提供的实现覆盖了它唯一的方法 apply()
。并将此对象分配给 Function<String, String>
引用。
Function<String,String> fct = new Function<>() {
@Override
public String apply(String s) {
return s;
}
};
它是一个不可变的对象,拥有一个 public static final Function<String,String> REUSE_OFTEN = s -> String.valueOf(s)
确实有意义,因为您可以重复使用相同的对象来对不同的输入应用此操作。
I.e., if I do List lst = new ArrayList<>() I implement an
ArrayList object.
你实例化一个 ArrayList
而不是。
What is the object that gets created if I do Function
fct = s -> s? And is that object immutable, i.e. does it make sense to
have a public static final Function REUSE_OFTEN = s ->
String.valueOf(s)?
Lambda 在字节码方面与匿名 classes 不同,在 behavior/functioning 方面也不相同。最后一个足够接近但不完全相同。
这里有两种方法做同样的事情,一种使用 lambda,另一种使用匿名 class :
public class CompareBoth {
public void lambda() {
Function<String,String> fct = s -> s;
fct.apply("a");
}
public void anonymousClass() {
Function<String,String> fct = new Function<String, String>() {
@Override
public String apply(String t) {
return t;
}
};
fct.apply("a");
}
}
这里是反汇编代码:
public class cli.CompareBoth {
public cli.CompareBoth();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void lambda();
Code:
0: invokedynamic #2, 0 // InvokeDynamic #0:apply:()Ljava/util/function/Function;
5: astore_1
6: aload_1
7: ldc #3 // String a
9: invokeinterface #4, 2 // InterfaceMethod java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object;
14: pop
15: return
public void anonymousClass();
Code:
0: new #5 // class cli/CompareBoth
3: dup
4: aload_0
5: invokespecial #6 // Method cli/CompareBoth."<init>":(Lcli/CompareBoth;)V
8: astore_1
9: aload_1
10: ldc #3 // String a
12: invokeinterface #4, 2 // InterfaceMethod java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object;
17: pop
18: return
}
我们可以看到 JVM 对它们的处理方式不同。
What is the actual object that gets implemented ?
创建 lambda 时会执行此 JVM 指令:
0: invokedynamic #2, 0 // InvokeDynamic
#0:apply:()Ljava/util/function/Function;
Java7中引入的InvokeDynamic
被指定为字节码指令,通过动态方法调用促进动态语言(对于JVM)的实现。
您可以阅读 this javaworld page 以获得更多信息。
现在,随着你的发展,这真的很重要吗?
在大多数情况下,它不会。
功能接口在功能上与匿名接口非常接近,但有许多细微差别。
从概念上讲,我认为这样考虑是可以接受的。
关于函数式接口不变性:
函数式接口可能有一个状态,但被设计为不可变的。
因此,如果有意义,您可以重复使用它们。
但是InvokeDynamic
可能会被JVM优化。
所以你不应该为了节省一些对象而在你的代码中重用它们。
而不是将功能接口提取到常量或变量中,因为它使事情更清楚或避免重复。
我是 Java 中的 Lambda 表达式的新手,所以如果这个问题看起来很愚蠢,请不要反应太过苛刻: 实现的实际对象是什么我把它分配给一个FunctionalInterface
?即,如果我执行 List<String> lst = new ArrayList<>()
,我将实现一个 ArrayList
对象。如果我这样做 Function<String,String> fct = s -> s
,创建的对象是什么?该对象是不可变的吗,即 public static final Function<String,String> REUSE_OFTEN = s -> String.valueOf(s)
?
当您编写 lambda 表达式时 -
Function<String,String> fct = s -> s;
它只是创建了一个匿名的 class,实现了 Function<String, String>
接口,并用 s -> s
提供的实现覆盖了它唯一的方法 apply()
。并将此对象分配给 Function<String, String>
引用。
Function<String,String> fct = new Function<>() {
@Override
public String apply(String s) {
return s;
}
};
它是一个不可变的对象,拥有一个 public static final Function<String,String> REUSE_OFTEN = s -> String.valueOf(s)
确实有意义,因为您可以重复使用相同的对象来对不同的输入应用此操作。
I.e., if I do List lst = new ArrayList<>() I implement an ArrayList object.
你实例化一个 ArrayList
而不是。
What is the object that gets created if I do Function fct = s -> s? And is that object immutable, i.e. does it make sense to have a public static final Function REUSE_OFTEN = s -> String.valueOf(s)?
Lambda 在字节码方面与匿名 classes 不同,在 behavior/functioning 方面也不相同。最后一个足够接近但不完全相同。
这里有两种方法做同样的事情,一种使用 lambda,另一种使用匿名 class :
public class CompareBoth {
public void lambda() {
Function<String,String> fct = s -> s;
fct.apply("a");
}
public void anonymousClass() {
Function<String,String> fct = new Function<String, String>() {
@Override
public String apply(String t) {
return t;
}
};
fct.apply("a");
}
}
这里是反汇编代码:
public class cli.CompareBoth {
public cli.CompareBoth();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
public void lambda();
Code:
0: invokedynamic #2, 0 // InvokeDynamic #0:apply:()Ljava/util/function/Function;
5: astore_1
6: aload_1
7: ldc #3 // String a
9: invokeinterface #4, 2 // InterfaceMethod java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object;
14: pop
15: return
public void anonymousClass();
Code:
0: new #5 // class cli/CompareBoth
3: dup
4: aload_0
5: invokespecial #6 // Method cli/CompareBoth."<init>":(Lcli/CompareBoth;)V
8: astore_1
9: aload_1
10: ldc #3 // String a
12: invokeinterface #4, 2 // InterfaceMethod java/util/function/Function.apply:(Ljava/lang/Object;)Ljava/lang/Object;
17: pop
18: return
}
我们可以看到 JVM 对它们的处理方式不同。
What is the actual object that gets implemented ?
创建 lambda 时会执行此 JVM 指令:
Java7中引入的0: invokedynamic #2, 0 // InvokeDynamic #0:apply:()Ljava/util/function/Function;
InvokeDynamic
被指定为字节码指令,通过动态方法调用促进动态语言(对于JVM)的实现。
您可以阅读 this javaworld page 以获得更多信息。
现在,随着你的发展,这真的很重要吗?
在大多数情况下,它不会。
功能接口在功能上与匿名接口非常接近,但有许多细微差别。
从概念上讲,我认为这样考虑是可以接受的。
关于函数式接口不变性:
函数式接口可能有一个状态,但被设计为不可变的。
因此,如果有意义,您可以重复使用它们。
但是InvokeDynamic
可能会被JVM优化。
所以你不应该为了节省一些对象而在你的代码中重用它们。
而不是将功能接口提取到常量或变量中,因为它使事情更清楚或避免重复。