Java 8中的本地类构造函数的方法引用如何工作?

Cag*_*tay 6 java lambda java-8

这里的示例代码无法在Java 8(1.8.0_40)中编译,但在Eclipse 4.4 JDT独立编译器(Bundle-Version:3.10.0.v20140604-1726)中编译并成功运行:

import java.util.Arrays;

import org.junit.Test;

import static org.junit.Assert.assertEquals;

/**
 * Test method references to local class constructors.
 */
public class LocalClassTest {

  public long sumOfLengths(String[] input) {
    class Sum {
      final long value;

      Sum(long value) {
        this.value = value;
      }

      Sum(Sum left, Sum right) {
        this.value = left.value + right.value;
      }

      Sum add(String s) {
        return new Sum(value + s.length());
      }
    }

    return Arrays.stream(input)
                 .reduce(new Sum(0), Sum::add, Sum::new)
               .value;
  }

  static String[] input =
      {
          "a", "ab", "abc"
      };

  @Test
  public void localClassConstructorMethodRefs() {
    assertEquals(sumOfLengths(input), 6);
  }
}
Run Code Online (Sandbox Code Playgroud)

javac 吐出以下错误信息:

Error:(32, 25) java: incompatible types: cannot infer type-variable(s) U
    (argument mismatch; invalid constructor reference
      cannot access constructor Sum(Sum,Sum)
        an enclosing instance of type LocalClassTest is not in scope)
Run Code Online (Sandbox Code Playgroud)

通过JLS 15.9.2(确定封闭实例)和15.13.3(方法引用的运行时评估)阅读,我不明白为什么这应该无法编译,并且错误消息似乎完全错误,因为我可以手动构建一个Sum实例在同一方法中就好了.

我发现之前的一个问题内部类的构造函数引用在运行时看起来与VerifyError失败相关,并且那里的链接JDK问题(https://bugs.openjdk.java.net/browse/JDK-8037404)表明了一系列问题.这方面的编译问题; 也许这是一个更普遍的问题的另一个例子.不过,我不确定我是否正确阅读规范; 这可以用另一种方式工作吗?

Bre*_*ail 4

这看起来确实像是处理本地类(方法内的类声明)的编译器错误。如果更改为内部类(将类声明移到方法之外),那么它可以正常工作。您可以同时将其更改为静态类,这会稍微减少开销。

(内部类和本地类都有对包含类的隐式引用,这意味着构造函数有一个“隐藏”的第一个参数,您可以使用 javap 看到它。我怀疑编译器知道在Sum::new使用内部类,但只是缺少对本地类执行相同操作的逻辑。)