异常的原因java.lang.VerifyError:操作数堆栈上的错误类型

dGa*_*and 18 java lambda java-8

下面简单的java代码在操作数堆栈异常发送 java.lang.VerifyError:Bad类型

public class TestJavaCodes {

    int parentData = 0;

    public void init() {
        A ob = new B();
    }

    public static void main(String[] args) {

        TestJavaCodes testJavaCodes = new TestJavaCodes();
        testJavaCodes.init();
    }

    public static class A {
        public A(MyLambdaFunc lambdaFunc) {
        }
    }

    public class B extends A {

        public B() {
            super((data1, type) -> {
                parentData = 1;
            });
        }
    }

    @FunctionalInterface
    public static interface MyLambdaFunc {
        public void onData(String data, int type);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我删除代码

parentData = 1
Run Code Online (Sandbox Code Playgroud)

来自B构造函数,异常不会来.

任何人都可以说出原因吗?

Tag*_*eev 15

似乎这些代码根本不应该编译.我最小化了你的代码:

public class CompilerBug {
    int var = 0;

    public static void main(String[] args) {
        new CompilerBug().new Inner();
    }

    public class Inner {
        public Inner(Runnable r) {}

        public Inner() {
            this(() -> {
                var = 1;
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它是由javac 1.8.0.25,1.8.0.40和1.9b57编译而没有问题的.每个编译版本在启动时都会产生相同的输出:

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  Location:
    CompilerBug$Inner.<init>(LCompilerBug;)V @3: invokedynamic
  Reason:
    Type uninitializedThis (current frame, stack[2]) is not assignable to 'CompilerBug$Inner'
  Current Frame:
    bci: @3
    flags: { flagThisUninit }
    locals: { uninitializedThis, 'CompilerBug' }
    stack: { uninitializedThis, 'CompilerBug', uninitializedThis }
  Bytecode:
    0000000: 2a2b 2aba 0003 0000 b700 04b1

        at CompilerBug.main(CompilerBug.java:5)
Run Code Online (Sandbox Code Playgroud)

此代码不是由ECJ编译器编译的.它报告编译错误:

----------
1. ERROR in C:\projects\Test\src\CompilerBug.java (at line 12)
    this(() -> {
         ^^^^^
Cannot refer to 'this' nor 'super' while explicitly invoking a constructor
----------
1 problem (1 error)
Run Code Online (Sandbox Code Playgroud)

所以它看起来像是javac编译器中的一个错误:它应该返回一个编译错误(如ECJ).

我没有在OpenJDK bug跟踪器中找到类似的bug,因此通过webform提交了一个新的bug报告.如果Java人员正在阅读此内容,则分配的内部审阅ID为JI-9021379.

更新:接受错误报告(JDK-8129740)


Hol*_*ger 12

出现问题的原因是你的lambda表达式没有引用this或者是外部this成员的成员.你写过类似的吗? thisB

public class B extends A {
    int innerData;
    public B() {
        super((data1, type) -> innerData = 1);
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器毫无疑问拒绝了它,因为访问innerData意味着访问this.

关于外部实例的观点是它是一个常量,当内部实例尚未完全构造时它甚至可用.因此接受代码是正确的,但不幸的是编译器生成的代码试图通过内部类实例的隐式字段访问外部实例,因此lambda表达式需要内部类的实例并尝试使用未完全构造的内部类实例产生错误.

可以很容易地证明代码可以正确编译:

public class B extends A {
    public B() {
        this(TestJavaCodes.this);
    }
    private B(TestJavaCodes outer) {
        super((data1, type) -> outer.parentData = 1);
    }
}
Run Code Online (Sandbox Code Playgroud)

通过这个小的更改,lambda表达式引用外部实例而不访问内部实例,并且不会出现错误.

  • 你是对的,这样的代码也可以工作:`public static class A {public A(int x){}} public class B extends A {public B(){super(parentData = 1); }.因此,在调用超类之前,甚至允许外部类的显式更改.似乎ECJ编译器也存在错误. (2认同)