40

Android が開発者に静的内部クラスを使用させることを好む多くの Java コードを目にします。特に、カスタム ListAdapter のViewHolderパターンのようなパターンの場合。

静的クラスと非静的クラスの違いがわかりません。私はそれについて読んだことがありますが、パフォーマンスやメモリフットプリントに関心がある場合は意味がないようです.

4

5 に答える 5

72

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(){}
}
于 2010-06-24T06:19:46.930 に答える
26

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

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

これはメモリやパフォーマンスにどのように影響しますか? 本当にわかりません。:)

于 2010-06-24T03:31:04.487 に答える
15

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

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

于 2010-06-24T02:50:49.947 に答える
7

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

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

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

外部クラスへの参照は内部クラスのctor引数であり、新しい非静的内部クラスオブジェクトを作成するには、外部クラスのインスタンスまたはからメンバー関数のようにctorを呼び出す必要があります。外部クラスのメンバー関数内。つまり、外側のクラスのインスタンスがなければ、内側のクラスのインスタンスを持つことはできません。

Outer.Inner in = new Outer().new Inner();
于 2010-06-24T10:26:28.667 に答える
5

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

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

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

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

于 2010-06-24T06:22:54.917 に答える