在Java中分配给功能接口的对象是什么?

时间:2018-01-12 21:39:21

标签: java functional-interface

我是Java中Lambda表达式的新手,所以如果这个问题显得很愚蠢,请不要太苛刻:如果我将它分配给{{1},实际的对象是什么? }?即,如果我FunctionalInterface,我实现了一个List<String> lst = new ArrayList<>()对象。如果我ArrayList,会创建什么对象?并且该对象是不可变的,即有Function<String,String> fct = s -> s

是否有意义

2 个答案:

答案 0 :(得分:2)

当你写一个lambda表达式 -

Function<String,String> fct = s -> s;

它只是创建一个实现Function<String, String>接口的匿名类,并使用apply()提供的实现覆盖其唯一的方法s -> s。并将此对象分配给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)是有意义的,因为你可以重用相同的对象来应用不同输入的这个操作。

答案 1 :(得分:1)

  

即,如果我做List lst = new ArrayList&lt;&gt;()我实现了   ArrayList对象。

您实例化了ArrayList

  

如果我执行Function,会创建什么对象   fct = s - &gt; S'并且该对象是不可变的,即它是否有意义   有一个公共静态最终函数REUSE_OFTEN = s - &gt;   将String.valueOf(S)?

在字节代码方面,Lambda与匿名类不同,在行为/功能方面也是如此。最后一个足够接近但不完全相同。

以下是两个执行相同操作的方法,一个使用lambda,另一个使用匿名类:

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$1
       3: dup
       4: aload_0
       5: invokespecial #6                  // Method cli/CompareBoth$1."<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对它们的区别对待。

  

实施的实际对象是什么?

创建lambda时,将执行此JVM指令:

  

0:invokedynamic#2,0 // InvokeDynamic         #0:申请:()Ljava / util的/功能/功能;

Java 7中引入的

InvokeDynamic被指定为字节码指令,通过动态方法调用来促进动态语言(用于JVM)的实现。 您可以阅读this javaworld page以获取更多信息。
现在,随着你的发展真的重要吗?
在大多数情况下,它没有 功能接口的功能非常接近匿名接口,但存在多种细微差别 从概念上讲,我认为以这种方式考虑它们是可以接受的。

关于功能界面不变性:

功能接口可能具有状态,但设计为不可变的。

所以如果有意义,你可以重复使用它们 但{J}可以优化InvokeDynamic 因此,您不应该在代码中重复使用它们,只是为了节省一些对象 而不是在常量或变量中提取函数接口,因为它使事情更清晰或避免重复。