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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30365106/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 09:29:37  来源:igfitidea点击:

Reason for the exception java.lang.VerifyError: Bad type on operand stack

javalambdajava-8

提问by dGayand

The below simple java code sends the java.lang.VerifyError: Bad type on operand stackexception

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

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);
    }
}

If I remove the code

如果我删除代码

parentData = 1

from B's constructor, the exception won't come.

fromB的构造函数,不会出现异常。

Can any one tell the reason for this?

任何人都可以说出这是什么原因吗?

采纳答案by Holger

The problem arises because your lambda expression does not reference thisor a member of thisbut a member of the outerthis. Had you written class Blike

出现问题是因为您的 lambda 表达式没有引用this或成员,this而是外部this. 假如你写的类B

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

the compiler rejected it without any doubts as accessing innerDataimplies accessing this.

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

The point about the outer instance is that it is a constant which is even available when the inner instance has not been fully constructed yet. So it's correct to accept the code but unfortunately the compiler generates code which attempts to access the outer instance via an implicit field of the inner class instance, thus the lambda expression requires an instance of the inner class and attempting to use the not fully constructed inner class instance produces the error.

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

It can be easily demonstrated that the code canbe compiled correctly:

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

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

with that small change, the lambda expression refers to the outer instance without accessing the inner instance and no error arises.

有了这个小改动,lambda 表达式就引用了外部实例,而无需访问内部实例,也不会出现错误。

回答by Tagir Valeev

Seems that such code should not compile at all. I minimized your code:

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

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;
            });
        }
    }
}

It's compiled without problems by javac 1.8.0.25, 1.8.0.40 and 1.9b57. Every compiled version produces the same output when launching:

它由 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)

This code is not compiled by ECJ compiler. It reports a compilation error:

此代码不是由 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)

So it looks like a bug in javac compiler: it should return a compilation error instead (like ECJ).

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

I did not find similar bug in OpenJDK bug tracker, so submitted a new bug report via webform. If Java folks are reading this, the internal review ID assigned is JI-9021379.

我在 OpenJDK bug tracker 中没有发现类似的 bug,所以通过 webform 提交了一个新的 bug 报告。如果 Java 人员正在阅读本文,则分配的内部 ID 为 JI-9021379。

Update:The bug report is accepted (JDK-8129740)

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