带注释参数的私有方法的 Android java.lang.VerifyError

发布于 2024-09-04 06:41:12 字数 3009 浏览 4 评论 0原文

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

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 错误吗?

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

Test.java:

public class Test {

    private void bar(@Some String a) {}

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

Some.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();
    }
}

Stack trace:

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)

I have a very simple project that compiles, but can't be started on Emulator. The problem is with this method:

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

The issue can be avoided if annotation removed

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

or the method visibility changed:

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

Any idea what is wrong with original method? Is this a dalvik bug, or?

If some one whould like to experiment with code, here it is:

Test.java:

public class Test {

    private void bar(@Some String a) {}

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

Some.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();
    }
}

Stack trace:

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

半边脸i 2024-09-11 06:41:12

这实际上是 Eclipse 3.5 编译器的一个错误(Bug 289576),它发生了变化带有带注释参数的方法的 private 修饰符,以便该方法成为“包私有”方法。因此,您的:

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

.class 文件中变为:

void bar(@Some String a) {…}

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

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

This is actually a bug of Eclipse 3.5 compiler (Bug 289576) which changes the private modifier of the method with annotated argument so that method becomes a "package-private" one. So your:

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

in the .class file becomes:

void bar(@Some String a) {…}

The changed method however is still invoked by the invokespecial JVM instruction, which is intended only for private methods invocations (also for some other non-method stuff), but surprisingly works also for "package-private" methods on Sun/Oracle JVM.
During Android .class => .dex translation invokespecial JVM instruction is converted to invoke-direct Dalvik instruction, which can only invoke private methods and constructors. As the bar() method has become a package-visible method, invoke-direct can't find it and throws NoSuchMethodError.

The solution is to use Eclipse 3.6+, or a javac compiler (through build.xml ant script).

我很OK 2024-09-11 06:41:12

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

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

My guess is that "private void bar(String) {}" is marked fully inlineable by the compiler and never actually created. Precisely why the reference in foo() then occurs (vs inlining) is hard to say, but likely the annotation screws up the compiler's bookkeeping.

(The clue here is "private" -- private methods are almost always good candidates for inlining, especially ones with void bodies.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文