web-dev-qa-db-ja.com

Androidが静的クラスを好む理由

JavaコードここでAndroidは開発者に静的内部クラスを使用させることを好む。特に ViewHolderパターン カスタムListAdapters。

静的クラスと非静的クラスの違いは何なのかわかりません。私はそれについて読みましたが、パフォーマンスやメモリフットプリントに関しては意味がありません。

39
Jeremy Edwards

Android開発者だけではありません...

非静的内部クラスは常に、それを囲むオブジェクトへの暗黙的な参照を保持します。その参照が必要ない場合は、メモリを消費するだけです。このことを考慮:

class Outer {
    class NonStaticInner {}
    static class StaticInner {}
    public List<Object> foo(){ 
        return Arrays.asList(
            new NonStaticInner(),
            new StaticInner()); 
    }
}

コンパイルすると、次のようになります。

class Outer {
    Outer(){}
    public List<Object> foo(){ 
        return Arrays.asList(
            new Outer$NonStaticInner(this),
            new StaticInner()); 
    }
}
class Outer$NonStaticInner {
    private final Outer this$0;
    Outer$NonStaticInner(Outer enclosing) { this$0 = enclosing; }
}
class Outer$StaticInner {
    Outer$StaticInner(){}
}
70
gustafc

静的内部クラスと非静的内部クラスの主な違いは、非静的内部クラスが、プライベートであっても外部クラスの他のメンバーにアクセスできることです。非静的内部クラスは、外部クラスの「一部」です。外部クラスのインスタンスがなければ、作成も存在もできません。この結果、外部クラスのインスタンスが破棄されると、非静的内部クラスのインスタンスが破棄されます。

一方、静的内部クラスは、通常の外部クラスとまったく同じです。自分で生きて死ぬ。内部クラスが存在するために外部クラスのインスタンスは必要ありません。つまり、彼ら自身のライフサイクルもあります。ガベージコレクターが破棄することを決定すると、それらは破棄されます。

これはメモリやパフォーマンスにどのように影響しますか?本当に分からない。 :)

26
Jere.Jones

静的内部クラス(つまり、キーワードstaticを使用して別のクラス内で宣言されたクラス)は、パッケージの名前空間を汚染しないことを除いて、「通常の」クラスと非常に似ています。それが(唯一の)違いとメリットであり、それがAndroidで見られる理由だと思います。

クラスの目的がメインクラスに限定されているが、インスタンスに依存していない場合は、静的内部クラスを使用します。これは一般的に良い方法と考えられています。

15
Viliam

非静的内部クラスインスタンスは外部クラスインスタンスへの参照を保持しますが、静的内部クラスインスタンスは保持しません。

非表示の参照はメモリリークを引き起こす可能性があるため、これはアプリケーションのメモリフットプリントに関連します。ガベージコレクタは、参照がなくなるまで外部クラスインスタンスを収集できません。また、追加のリファレンス自体にもメモリが必要です。これは、多数のインスタンスが使用される場合に関連する可能性があります。

class Outer{
    class Inner{//Only works with non static inner class
          public Outer getOuter(){return Outer.this;}
    }
}

外部クラスへの参照は内部クラスのctor引数であり、外部クラスのインスタンスのメンバー関数のように、または外部クラスのメンバー関数内。つまり、外部クラスのインスタンスがないと、内部クラスのインスタンスを作成できません。

Outer.Inner in = new Outer().new Inner();
7
josefx

内部クラスを逆コンパイルする(またはデバッガーを使用して監視する)と、それらの作成に使用された外部クラスのインスタンスにアクセスするための生成されたコードがあることがわかります。このためのオーバーヘッドは、追加のポインター用のより多くのメモリ、テスト用の追加のポインターによるガベージコレクション用のより多くのcpu、および選択を単純化したい場合は、より長いコンパイル時間です。非静的内部クラスのインスタンスを作成するには、外部クラスのインスタンスを作成する必要があるため、少し複雑になります。

静的内部クラスと非静的内部クラスの両方の可視性を制御できます。通常、それらの実装が外部クラスの内部の詳細に強く関連付けられており、開発者がコードを再利用できるとは考えていない場合、それらはプライベートです。この意味で、それらはプライベート関数よりも優れていません。 Map.Entryのような場合、内部クラスはパブリックである可能性があります。内部クラスは、クラスによって公開されているインターフェースに強く接続されており、開発者はMap.Entryが何らかのMapなしで使用できるとは考えていません。どちらのタイプも外部クラスのプライベートメンバーにアクセスでき、外部クラスは内部クラスのプライベートメンバーにアクセスできます。

静的および非静的内部クラスのインスタンスは、他のすべてのクラスと同様にガベージコレクションされます。外部クラスのガベージコレクションと内部クラスのガベージコレクションの間に特別な関係はありません。

SwingまたはAndroidのようなUIクラス実装の場合、それらはプライベート関数のように扱われるため、静的内部クラスが表示されます。これらのクラスは、外部クラスの外部での再利用性のために開発されておらず、外部クラスの内部実装これらを公開し、外部クラス要件の特定のコンテキストよりも多くのケースで機能できることを確認する理由はありません。

5
shoren