gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 22:47:25 27 4
gpt4 key购买 nike

我正在使用 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<Object, Object> i) {
System.out.println(i.apply(null));
}
}
}

最佳答案

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

private void runTest() {
Worker worker = new Worker();
run(() -> worker.print(field -> new SomeClass(field)));
Function<Object, Object> 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 translation ,了解内部工作。我仍然不太清楚 lambda 和方法引用是如何翻译的。

我找到了一个 thread in lambda mailing list关于类似的问题。另外,this SO post也有关系。

以下 runtTest() 方法:

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

Function<Object, Object> 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."<init>":()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 方法。我猜想我们可以肯定地说这是一个错误。或许您可以提交一份。

关于java - 内部类的构造函数引用在运行时因 VerifyError 而失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22738962/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com