内部类的构造函数引用在运行时因VerifyError而失败

我正在使用lambda ctx -> new SpectatorSwitcher(ctx)为内部类构造函数创建供应商。 IntelliJ建议我将它改为SpectatorSwitcher::new 。 SpectatorSwitcher是我正在使用的类的非静态内部类。建议的代码编译得很好(使用maven)但我在执行时得到以下VerifyError:

 Exception in thread "main" java.lang.VerifyError: Bad type on operand stack Exception Details: Location: Test.lambda$runTest$8(LTest$Worker;)V @2: invokedynamic Reason: Type 'Test$Worker' (current frame, stack[1]) is not assignable to 'Test' Current Frame: bci: @2 flags: { } locals: { 'Test$Worker' } stack: { 'Test$Worker', 'Test$Worker' } Bytecode: 0000000: 2a2a ba00 0b00 00b6 000c b1 at java.lang.Class.getDeclaredMethods0(Native Method) at java.lang.Class.privateGetDeclaredMethods(Class.java:2688) at java.lang.Class.getMethod0(Class.java:2937) at java.lang.Class.getMethod(Class.java:1771) at sun.launcher.LauncherHelper.validateMainClass(LauncherHelper.java:544) at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:526) 

为什么javac / maven在编译时没有失败但仍然产生无效的字节代码?

编辑:问题似乎比简单调用复杂得多,这是重现它所需的代码:

 import java.util.function.Function; /** * @author Yawkat */ public class Test { public static void main(String[] args) { new Test().runTest(); } private void runTest() { Worker worker = new Worker(); run(() -> worker.print(field -> new SomeClass(field))); run(() -> worker.print(SomeClass::new)); } private void run(Runnable runnable) { runnable.run(); } private class SomeClass { final Object field; SomeClass(Object field) { this.field = field; } } private static class Worker { void print(Function i) { System.out.println(i.apply(null)); } } } 

即使把我的头撞到字节码上将近一个小时,我也无法得出一个合理的结论,为什么会发生这种情况。 令人惊讶的是,将您的方法更改为:

 private void runTest() { Worker worker = new Worker(); run(() -> worker.print(field -> new SomeClass(field))); Function function = SomeClass::new; run(() -> worker.print(function)); } 

工作良好。 另外,摆脱run()方法调用,只调用worker.print()

 private void runTest() { Worker worker = new Worker(); worker.print(field -> new SomeClass(field)); worker.print(SomeClass::new); } 

也有效。

看起来,在您的情况下使用构造函数引用无法将Test类的封闭实例传递给所需的SomeClass构造函数。 虽然这里的两个案例能够将Test实例传递给SomeClass构造函数。

但我无法说出具体原因。 上述推理可能是错误的。 但是在完成那些工作方法后我才刚刚谈到这一点。

您可能想要通过lambda翻译 ,了解内部工作。 我还不太清楚如何翻译lambdas和方法引用。

我在lambda邮件列表中找到了一个关于类似问题的线程 。 此外, 这个SOpost也是相关的。

以下runtTest()方法:

 public void runTest() { Worker worker = new Worker(); run(() -> worker.print((field) -> new SomeClass(field))); run(() -> worker.print(SomeClass::new)); Function func = SomeClass::new; run(() -> worker.print(func)); worker.print(SomeClass::new); } 

编译为以下字节码:

  public void runTest(); Code: 0: new #2 // class SO$Worker 3: dup 4: invokespecial #3 // Method SO$Worker."":()V 7: astore_1 8: aload_0 9: aload_0 10: aload_1 11: invokedynamic #4, 0 // InvokeDynamic #0:run:(LSO;LSO$Worker;)Ljava/lang/Runnable; 16: invokevirtual #5 // Method run:(Ljava/lang/Runnable;)V 19: aload_0 20: aload_1 21: invokedynamic #6, 0 // InvokeDynamic #1:run:(LSO$Worker;)Ljava/lang/Runnable; 26: invokevirtual #5 // Method run:(Ljava/lang/Runnable;)V 29: aload_0 30: invokedynamic #7, 0 // InvokeDynamic #2:apply:(LSO;)Ljava/util/function/Function; 35: astore_2 36: aload_0 37: aload_1 38: aload_2 39: invokedynamic #8, 0 // InvokeDynamic #3:run:(LSO$Worker;Ljava/util/function/Function;)Ljava/lang/Runnable; 44: invokevirtual #5 // Method run:(Ljava/lang/Runnable;)V 47: aload_1 48: aload_0 49: invokedynamic #7, 0 // InvokeDynamic #2:apply:(LSO;)Ljava/util/function/Function; 54: invokevirtual #9 // Method SO$Worker.print:(Ljava/util/function/Function;)V 57: return 

我只能看到第二个run()方法调用没有传递LSO参数,而其他人传递它。 您可以运行命令javap -c -s -verbose Test ,查看#0#1等的Bootstrap方法。我想我们可以肯定地说这是一个bug。 也许你可以提交一个。