3

コンパイルできる非常に単純なプロジェクトがありますが、エミュレーターで開始できません。問題はこの方法にあります:

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バグですか、それとも?

コードを試してみたい人は、次のとおりです。

テスト.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)
4

2 に答える 2

3

これは実際には Eclipse 3.5 コンパイラのバグ (バグ 289576 ) でありprivate、メソッドが「パッケージ プライベート」になるように、注釈付きの引数を持つメソッドの修飾子を変更します。だからあなた:

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

.classファイルでは次のようになります。

void bar(@Some String a) {…}

ただし、変更されたメソッドは、private メソッドの呼び出しのみを目的とした (他のメソッド以外のものも対象とする) invokespecial JVM 命令によって引き続き呼び出されますが、驚くべきことに、Sun/Oracle JVM の「package-private」メソッドに対しても機能します。
Android .class => .dex変換中、 invokespecial JVM 命令は、プライベート メソッドとコンストラクターのみを呼び出すことができる直接呼び出しDalvik 命令に変換されます。bar()メソッドがパッケージから見えるメソッドになったので、invoke -directはそれを見つけることができず、 をスローしNoSuchMethodErrorます。

解決策は、Eclipse 3.6+、または javac コンパイラー ( build.xmlant スクリプトを介して) を使用することです。

于 2011-08-30T11:11:33.117 に答える
0

私の推測では、「private void bar(String) {}」はコンパイラによって完全にインライン化可能とマークされており、実際には作成されていません。foo() での参照が発生する正確な理由 (インライン化に対して) を言うのは難しいですが、おそらく注釈がコンパイラの簿記を台無しにします。

(ここでの手がかりは「プライベート」です。プライベート メソッドは、ほとんどの場合、インライン化の良い候補であり、特に void ボディを持つメソッドです。)

于 2011-05-28T01:05:35.597 に答える