7

内部クラスは、それを囲むクラスへの参照を保持するため、Android では推奨されないことを認識しています。ただし、Java では、内部クラスが参照されなくなった場合にのみ外部クラスが GC されます。つまり、Android では、外部アクティビティ クラスに内部クラスへの非静的参照がある場合、参照を保持していない場合にのみアクティビティを破棄できるため、内部クラスは外部アクティビティ クラスよりも長く存在することはできません。もはや内部クラスに(少なくともそれが私が推測していることです)。では、非静的内部クラスを使用する際の問題は何ですか (Java から推測した場合、外部アクティビティよりも明らかに長く存在することはできないため)。何か不足していますか?

ありがとう!

4

2 に答える 2

8

この簡単な例を考えてみましょう

class Leaker 
{
    public static Object leakedObj;
}

class MyActivity extends Activity
{
     public class MyInnerClass { ... }

     void onCreate(Bundle savedState) 
     {
        Leaker.leakedObj = new MyInnerClass();
        //The activity now won't be GCed until Leaker.leakedObj is cleared.          
     }
}

アクティビティのコンテキスト外で、内側の非静的クラスを簡単に渡すことができます。アクティビティのライフサイクル外のオブジェクトに内部クラスを渡さない限り、問題はありません。ただし、内部クラスを介してアクティビティをリークすることは確かに可能です。

于 2012-04-11T19:04:23.297 に答える
6

Google の方が適切に説明できるので、言い換えはしません。

仮定: 親クラスはFoo、内部クラスはFoo$Inner:

問題は、VM が Foo$Inner から Foo のプライベート メンバーへの直接アクセスを違法であると見なすことです。これは、Java 言語では内部クラスが外部クラスのプライベート メンバーにアクセスできるにもかかわらず、Foo と Foo$Inner は異なるクラスであるためです。ギャップを埋めるために、コンパイラはいくつかの合成メソッドを生成します。

/*package*/ static int Foo.access$100(Foo foo) {
    return foo.mValue;
}
/*package*/ static void Foo.access$200(Foo foo, int value) {
    foo.doStuff(value);
}

内部クラス コードは、mValue フィールドにアクセスする必要があるとき、または外部クラスで doStuff メソッドを呼び出す必要があるときはいつでも、これらの静的メソッドを呼び出します。これが意味することは、上記のコードは、アクセサー メソッドを介してメンバー フィールドにアクセスしているケースに要約されるということです。前に、アクセサーがフィールドへの直接アクセスよりも遅いことについて説明したので、これは特定の言語イディオムが「目に見えない」パフォーマンス ヒットをもたらす例です。

パフォーマンスのホットスポットでこのようなコードを使用している場合は、内部クラスによってアクセスされるフィールドとメソッドをプライベート アクセスではなくパッケージ アクセスを持つように宣言することで、オーバーヘッドを回避できます。残念ながら、これはフィールドが同じパッケージ内の他のクラスから直接アクセスできることを意味するため、パブリック API ではこれを使用しないでください。

ソース: https://developer.android.com/training/articles/perf-tips.html#PackageInner

于 2012-04-11T19:04:43.707 に答える