【问题标题】:Android java.lang.VerifyError for private method with annotated argument带有注释参数的私有方法的Android java.lang.VerifyError
【发布时间】:2011-02-28 11:50:34
【问题描述】:

我有一个可以编译的非常简单的项目,但无法在模拟器上启动。问题出在这个方法上:

private void bar(@Some String a) {} // java.lang.VerifyError

如果去掉注释,这个问题就可以避免

private void bar(String a) {} // OK

或方法可见性改变:

void bar(@Some String a) {} // OK
public void bar(@Some String a) {} // OK
protected void bar(@Some String a) {} // OK

知道原始方法有什么问题吗?这是一个dalvik bug,还是?

如果有人想尝试代码,这里是:

Test.java:

public class Test {

    private void bar(@Some String a) {}

    public void foo() {
        bar(null);
    }
}

一些.java:

public @interface Some {}

MainActivity.java:

public class MainActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        new Test().foo();
    }
}

堆栈跟踪:

ERROR/dalvikvm(1358): Could not find method com.my.Test.bar, referenced from method com.my.Test.foo
WARN/dalvikvm(1358): VFY: unable to resolve direct method 11: Lcom/my/Test;.bar (Ljava/lang/String;)V
WARN/dalvikvm(1358): VFY:  rejecting opcode 0x70 at 0x0001
WARN/dalvikvm(1358): VFY:  rejected Lcom/my/Test;.foo ()V
WARN/dalvikvm(1358): Verifier rejected class Lcom/my/Test;
DEBUG/AndroidRuntime(1358): Shutting down VM
WARN/dalvikvm(1358): threadid=3: thread exiting with uncaught exception (group=0x4000fe70)
ERROR/AndroidRuntime(1358): Uncaught handler: thread main exiting due to uncaught exception
ERROR/AndroidRuntime(1358): java.lang.VerifyError: com.my.Test
ERROR/AndroidRuntime(1358):     at com.my.MainActivity.onCreate(MainActivity.java:13)
ERROR/AndroidRuntime(1358):     at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
ERROR/AndroidRuntime(1358):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2231)
ERROR/AndroidRuntime(1358):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
ERROR/AndroidRuntime(1358):     at android.app.ActivityThread.access$1800(ActivityThread.java:112)
ERROR/AndroidRuntime(1358):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
ERROR/AndroidRuntime(1358):     at android.os.Handler.dispatchMessage(Handler.java:99)
ERROR/AndroidRuntime(1358):     at android.os.Looper.loop(Looper.java:123)
ERROR/AndroidRuntime(1358):     at android.app.ActivityThread.main(ActivityThread.java:3948)
ERROR/AndroidRuntime(1358):     at java.lang.reflect.Method.invokeNative(Native Method)
ERROR/AndroidRuntime(1358):     at java.lang.reflect.Method.invoke(Method.java:521)
ERROR/AndroidRuntime(1358):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
ERROR/AndroidRuntime(1358):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
ERROR/AndroidRuntime(1358):     at dalvik.system.NativeStart.main(Native Method)

【问题讨论】:

    标签: java android annotations verifyerror


    【解决方案1】:

    我的猜测是“private void bar(String) {}”被编译器标记为完全可内联,并且从未实际创建。 foo() 中引用的确切原因(与内联相比)很难说,但很可能注释会搞砸编译器的簿记。

    (这里的线索是“私有”——私有方法几乎总是适合内联的候选方法,尤其是那些具有空体的方法。)

    【讨论】:

      【解决方案2】:

      这实际上是 Eclipse 3.5 编译器 (Bug 289576) 的一个错误,它使用带注释的参数更改了方法的 private 修饰符,从而使该方法成为“包私有”的方法。所以你的:

      private void bar(@Some String a) {…}
      

      .class文件中变成:

      void bar(@Some String a) {…}
      

      然而,更改后的方法仍然由invokespecial JVM 指令调用,该指令仅适用于私有方法调用(也适用于其他一些非方法的东西),但令人惊讶的是,它也适用于 Sun 上的“包私有”方法/Oracle JVM。
      Android .class=> .dex 翻译时invokespecial JVM 指令转换为invoke-direct Dalvik 指令,只能调用私有方法和构造函数.由于bar() 方法已成为包可见方法,invoke-direct 找不到它并抛出NoSuchMethodError

      解决方案是使用 Eclipse 3.6+,或者 javac 编译器(通过build.xml ant 脚本)。

      【讨论】:

      • 我也发现这也发生在 Android Studio 中。但是,它没有任何注释。我将访问修饰符从私有更改为公共,并且像魅力一样工作。很奇怪。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多