Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/321.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/eclipse/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Eclipse编译器为lambda生成的重复方法_Java_Eclipse_Lambda_Java 8 - Fatal编程技术网

Java 使用Eclipse编译器为lambda生成的重复方法

Java 使用Eclipse编译器为lambda生成的重复方法,java,eclipse,lambda,java-8,Java,Eclipse,Lambda,Java 8,这条线 ((UnaryOperator<Integer>)o->o).toString(); 就其本身而言,这并没有什么值得注意的,这是Eclipse Java 8编译器中的另一个bug。然而,我对失败的细节很感兴趣。如果我们启用jdk.internal.lambda.dumpProxyClasses系统属性并检索生成的lambda类代码,使用javap对其进行解析将显示该类定义了两个相同的apply方法,其中一个被标记为桥接方法: 我理解,为了保持向后兼容性,泛型需要桥接方

这条线

((UnaryOperator<Integer>)o->o).toString();
就其本身而言,这并没有什么值得注意的,这是Eclipse Java 8编译器中的另一个bug。然而,我对失败的细节很感兴趣。如果我们启用
jdk.internal.lambda.dumpProxyClasses
系统属性并检索生成的lambda类代码,使用
javap
对其进行解析将显示该类定义了两个相同的
apply
方法,其中一个被标记为桥接方法:

我理解,为了保持向后兼容性,泛型需要桥接方法;然而,我无法理解Eclipse中的错误如何迫使JDK合成有缺陷的方法对

作为比较,如果我们稍微将Java行更改为:

((Object)((UnaryOperator<Integer>)o->o)).toString();
可能这实际上是JDK中的一个bug,但它不是由
javac
引起的吗

我正在OSX上使用
JavaC1.8.0\u20
,并使用带有Java8补丁的Eclipse开普勒SR2

更新:引导方法调用 Eclipse编译器负责发出正确的InvokedDynamic引导方法调用(lambda元工厂)。以下是失败案例的引导方法参数的外观:

BootstrapMethods:
      0: #39 invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
        Method arguments:
          #41 (Ljava/lang/Object;)Ljava/lang/Object;
          #44 invokestatic test/Test.lambda$0:(Ljava/lang/Integer;)Ljava/lang/Integer;
          #45 (Ljava/lang/Integer;)Ljava/lang/Integer;
          #46 4
          #47 1
          #48 (Ljava/lang/Object;)Ljava/lang/Object;
由于Brian的帮助,我现在清楚地看到上面最后两行造成了错误:

  • #47
    上的数字1表示“有一种桥接方法”
  • (Ljava/lang/Object;)Ljava/lang/Object#48
    上的code>描述了桥接方法的签名,这显然与主签名相同
为了进行比较,以下是工作情况:

BootstrapMethods:
      0: #53 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
        Method arguments:
          #55 (Ljava/lang/Object;)Ljava/lang/Object;
          #58 invokestatic test/Test.lambda$0:(Ljava/lang/Integer;)Ljava/lang/Integer;
          #59 (Ljava/lang/Integer;)Ljava/lang/Integer;

这里使用了更简单的
元工厂
方法,并且没有创建桥接方法。

根据您发布的堆栈跟踪,这几乎肯定是Eclipse代码生成中的一个bug,而不是JDK。您可以从捕获lambda(由ecj生成)的代码的
javap
列表中找到这一点。我想您会发现,它调用了替代元工厂(
altMetafactory
),它处理异常情况,例如可序列化lambda,由lambda对象实现的附加标记接口,或目标接口未处理的桥接方法

仅供参考,明确要求额外桥梁的情况如下:

  • 当目标接口需要桥接,但使用较旧的javac编译,因此桥接不存在于接口本身时,或者
  • 当目标类型和其他接口之间的交互需要桥接时

  • 这两种情况都很严重,应该很少发生。

    是的,我已经确定使用了
    altMetaFactory
    ,并且只在失败的情况下使用。我仍然找不到提供方法实现的代码;我甚至不知道在哪里可以找到它。它在恒定池中吗?另外,我希望lambda工厂机制足够高,不允许创建无效类。基本上,我试图深入了解lambda(meta)工厂的内部工作原理。如果您将静态引导args(常量池中的引导方法表,javap-v)的javap列表发布到altMetaFactory引导,我可以告诉您它应该说什么。bootstrap方法列表就在
    javap-v-c
    列表中的常量池之后;通过查看捕获所需lambda的
    invokedynamic
    指令,在表中找到正确的条目。我已经粘贴了它,但我已经感谢您回答我的问题。显然,问题发生在标记为
    #48
    的条目上。我已经与
    altMetaFactory
    的签名进行了交叉检查,这是“bridges”参数。是的,eclipse要求一个冗余桥接器。这从未向eclipse报告过。现在尝试关闭循环,我找不到任何发布版本的ecj,它为本例创建了涉及
    altMetaFactory
    的代码。听起来ecj和javac从Java8GA开始就在这里达成了一致(除非这个例子比上面显示的更多)。
    {
      public java.lang.Object apply(java.lang.Object);
        descriptor: (Ljava/lang/Object;)Ljava/lang/Object;
        flags: ACC_PUBLIC
        Code:
          stack=1, locals=2, args_size=2
             0: aload_1
             1: checkcast     #14                 // class java/lang/Integer
             4: invokestatic  #20                 // Method test/Test.lambda$0:(Ljava/lang/Integer;)Ljava/lang/Integer;
             7: areturn
    }
    
    BootstrapMethods:
          0: #39 invokestatic java/lang/invoke/LambdaMetafactory.altMetafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite;
            Method arguments:
              #41 (Ljava/lang/Object;)Ljava/lang/Object;
              #44 invokestatic test/Test.lambda$0:(Ljava/lang/Integer;)Ljava/lang/Integer;
              #45 (Ljava/lang/Integer;)Ljava/lang/Integer;
              #46 4
              #47 1
              #48 (Ljava/lang/Object;)Ljava/lang/Object;
    
    BootstrapMethods:
          0: #53 invokestatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
            Method arguments:
              #55 (Ljava/lang/Object;)Ljava/lang/Object;
              #58 invokestatic test/Test.lambda$0:(Ljava/lang/Integer;)Ljava/lang/Integer;
              #59 (Ljava/lang/Integer;)Ljava/lang/Integer;