Effective Java 3 rdエントリ24静的メンバタイプは非静的より優れている。

3853 ワード

ネスト類は他のクラスの内部に定義されているクラスです。ネスト類は外部サービスのためだけに存在するべきです。埋め込みタイプが他のいくつかの場合に役立つなら、彼はトップクラスであるべきです。4つの入れ子があります。スタティックメンバー類、スタティックメンバー類、ノンスタティックメンバー類、匿名類、ローカル類(local class)があります。一つだけは内部のものと考えられています。この項目は、どの種類のネスト類を使用するかを宣言します。なぜですか?
スタティックメンバークラスは、ネスト類の最も簡単な種類です。これは最も一般的なクラスと考えられています。ちょうど他のクラスの内部で声明しています。また、外部クラスのすべてのメンバーにアクセスすることができます。これらのメンバーはプライベートとして声明しています。静的なメンバクラスは、外部クラスの静的なメンバであり、他の静的なメンバのように同様のアクセス規則に従う。プライベートとして声明されているなら、彼は外部クラスの内部だけを訪問することができます。
静的な内部クラスの1つは、一般的に、外部クラスとの共同使用として、公開協力クラスとして使用される。例えば、計算機によってサポートされる動作を記述するエニュメレーションを考慮する(項目34)。Operationエニュメレーションは、Calculator類の公開静的なメンバーであるべきである。したがって、Calculatorのクライアントは、Calculator.Operation.PLUSおよびCalculator.Operation.MINUSのような名前を使用して、いくつかの動作を引用すべきである。
ステートメント構成において、静的および非静的なメンバクラスの唯一の違いは、静的なメンバ類がそれらの声明に修飾子staticを有していることである。文法上の類似性にもかかわらず、この2つのネスト類は非常に異なる。非静的なメンバクラスの各例は、クラスを含む外部のインスタンスに関連付けられている。非静的なメンバタイプの例示的な方法では、外部インスタンスの方法を呼び出すことができ、または限定的なthis構造体を使用して、外部インスタンスの参照[JLS,15.8.4]を得ることができる。ネストクラスのインスタンスが外部クラスから逸脱した例がある場合、ネストクラスは、外部インスタンスがなく、非静的なメンバクラスを作成することは不可能である必要がある。
メンバクラスのインスタンスが作成されると、非静的なメンバクラスのインスタンスとその外部のインスタンスとの接続が確立され、その後は変更されない。一般的に、この連絡は外部クラスの例示的な方法の内部から、非静的な構成子を呼び出して自動的に確立される。この連絡はマニュアルでenclosingInstance.new Members Classを使って作ることも可能です。非常に珍しいですが。あなたが予想しているように、この連絡は非静的なメンバタイプのインスタンスにおいて空間を占有し、その構造過程は時間を増加させる。
非静的なメンバタイプの1つの一般的な使用は、外部クラスのインスタンスが、ある関連しないクラスのインスタンスとして見なされることを可能にするAdapter[Gamma 95]を定義するものである。例えば、Mapインターフェースの実装は、一般に非静的なメンバタイプを使用して、彼らの集合ビューを実現し、それらはMap’s keySet、entrySet、valuesによって返される。同様に、セットインターフェース、例えばSetおよびListの実装は、通常、非静的なメンバークラスを使用して、それらのサブエージェントを実装する。
//             
public class MySet extends AbstractSet { 
    ... //          

    @Override public Iterator iterator() { 
        return new MyIterator(); 
    }

    private class MyIterator implements Iterator { 
        ...
    }
}
メンバークラスを定義すると、外部のインスタンスにアクセスする必要がないので、スタティックではなくスタティックなメンバークラスになるように、スタティックな修飾子を常にその声明に入れます。この修飾子を省略すると、各例には外部の例の追加的な参照が含まれます。前に述べたように、この参照を保存するのは時間と空間がかかります。もっと深刻なのは、外部のインスタンスが保存される可能性があります。元々はごみ収集に適しています。最終的なメモリ漏れは災難かもしれません。この引用は見えないので、通常は監視が難しいです。
プライベート静的メンバクラスの1つは、通常、それらの外部クラスによって表されるオブジェクトを表すコンポーネントとして使用される。例えば、Mapの例を考慮して、キーと値を関連付ける。多くのMapの例では、マッピング内の各キーペアに対して内部Entryの例がある。各entryは一つのマッピングに関連していますが、entryの方法はマッピングにアクセスする必要がありません。したがって、非静的なメンバークラスを使用して、entryを表現するのはもったいないことです。プライベート静的なメンバークラスが一番いいです。もしあなたがentry声明の中でstatic修饰符を無視したら、このマッピングはまだ仕事ですが、各entryは余分な対マッピングの参照を含みます。これは空間と時間を浪費します。
議論されているクラスが導出クラスの開示または保護されたメンバである場合には、静的および非静的なメンバクラスの間で正確に選択することが重要である。この場合、メンバクラスはAPI要素を導出するものであり、後続のリリースでは、後方互換性に違反することなく、非静的なメンバ類から静的なメンバ類に変更することができない。
あなたが予想しているように、匿名類には名前がありません。それは外のクラスのメンバーではありません。他のメンバーと一緒に声明するのではなく、使用中に声明と実用化されています。コードの中の1つの表現は合法的で、匿名クラスも許可されています。匿名クラスは、非静的環境で発生する場合にのみ、外部クラスがある。しかし、これらが静的環境で発生しても、定数変数以外の任意の静的メンバを持つことができず、定数式に初期化されたfinal元または文字列領域である。
匿名クラスのアプリケーションには多くの制限があります。それらが宣言されている場合以外は、それらを実行することはできません。instance ofテストができないか、またはあなたの名前が必要な他のことをします。複数のインターフェースを実装するために匿名クラスを宣言することはできません。または、1つのクラスを拡張し、1つのインターフェースを実現します。匿名クラスのクライアントを使用すると、そのスーパークラスから継承されたメンバー以外の任意のメンバーを呼び出すことができません。匿名クラスは式の中で発生するので、それらは短い(約10行またはより少ない)ままにしなければなりません。そうでなければ、可読性は損なわれます。
Javaにlambada(第6章)を追加する前に、匿名クラスは、小関数オブジェクト(function oject)と処理対象(process object)を容易に作成する好適な方法であったが、lamdaは現在より優れている(エントリ42)。匿名クラスの他の1つは、通常、静的工場法の実装である(参照エントリ20内のintArayAssList)。
ローカルクラスは4つの埋め込みタイプの中で最も少なく使用されます。ローカルクラスは、実際には、ローカル変数によって宣言されることができます。ローカルクラスと他のタイプの入れ子類は多くの同じ特徴があります。メンバーのように名前があります。また重複して使うことができます。匿名のクラスのように、それらが非静的なシナリオで定義される場合にのみ、外部のインスタンスがあり、静的なメンバを保護することができない。また匿名クラスのように、可読性を傷つけないように短く保つべきである。
簡単に要約すると、4つの異なるネスト類があり、それぞれの位置があります。もし一つのネスト類が単一の方法の外部に見られる必要がある場合、または長すぎて一つの方法の内部に適合しない場合、メンバークラスが使用される。メンバクラスの各インスタンスがその外部インスタンスの参照を必要とする場合、非静的になる。さもなくば、それを静にします。クラスが一つの方法の内部に属すると仮定すると、一つの位置からインスタンスを作成するだけでなく、このクラスの特性を記述する既存のクラスが必要であれば、匿名のクラスに変化する。さもなくば、それをローカルクラスに変えます。