一般的な方法であるすべてのオブジェクトの[Javaの研究ノート]効果的なJavaの(第3版)第3章

10 バー:カバレッジが等しいとき、共通の規則を遵守

オーバーライドが等しいことなく、クラスの各インスタンスに対してのみ自体に等しいです。

  • クラスの各インスタンスは、本質的にユニークです。
  • クラスは「論理的同等(論理的平等)」テスト機能を提供する必要はありません。
  • 親は、equalsメソッド、およびこのサブクラスのために完全に適切な親クラスの振る舞いをオーバーライドしています。
  • クラスは、プライベートプライベートまたはパッケージレベルであり、そのequalsメソッドが呼び出されることはありません決定することができます。

とき私は、equalsメソッドをカバーする必要がありますか?
  クラスが同じ論理的な概念(論理的平等)が含まれている場合-この概念は、オブジェクトのID(オブジェクトID)とは異なりますが、親クラスは、equalsメソッドを書き換えられていません。

  これは、典型的な状況のクラスの値(値クラス)に使用されます。

カバレッジがメソッドに等しい場合、それは一般的な仕様に準拠しなければなりません。ここでは仕様でのオブジェクトクラスのコメントは以下のとおりです。

  • 再帰性:x.equals(x)はtrueを返す必要があります
  • 対称性:x.equals(y)があれば真を返し、y.equals(x)がtrueを返す場合にのみ
  • 推移は:x.equals(y)がtrueを返す場合、y.equals(z)がtrueを返すについて、x.equals(z)はtrueを返す必要があります
  • 一貫性:equalsの比較で使用される情報が変更されていない場合について、x.equals(y)の複数の呼び出しは常にtrueを返すか、常にfalseを返す必要があります。
  • null以外の参照X用について、x.equals(ヌル)がfalseを返す必要があります

高品質を書くための秘訣は、equalsメソッド:

  • ==演算子は、オブジェクトの参照パラメータかどうかをチェックします。もしそうなら、それはtrueを返します。
  • 正しい型のパラメータかどうかを確認するためにinstanceof演算子を使用します。そうでない場合はfalseが返されます。
  • 正しい型にパラメータを変換します。
  • 各クラスキーフィールド(属性)の場合、パラメータは、オブジェクトの属性と一致するように対応するかどうかをチェックする属性。
  • ノンベースのfloat型またはdouble型のために、==演算子を比較するステップと、オブジェクト参照の属性は、この方法は、再帰的に呼び出し等しく;フロートプリミティブ型の場合、静的メソッドFloat.compare(フロート、フロート)を使用する。ためDouble.compare(二重、二重)メソッドを使用して二重プリミティブ型、。
  • メソッドのパフォーマンスが注文属性比較によって影響を受ける可能性が等しいです。最高のパフォーマンスを得るためには、最初に異なる属性を比較する必要がありますし、最も可能性の高いオーバーヘッドは比較的小さいプロパティです。

   例えば、文字列の例:

パブリック ブール等しい(anObjectオブジェクト){
     場合この == anObject){ 
         戻り 
    } 
    であれば(anObject instanceofの文字列){ 
        文字列anotherString = (文字列)anObject。
        INT、N = value.length。
        もし(N == anotherString.value.length){
             チャー V1 [] = 値。
            チャー V2 [] = anotherString.value。
            int型私= 0 ;
            しばらく(N - != 0){
                 もし!(V1 [I] = V2 [i])と
                     戻り 
                I ++ ; 
            } 
            を返す 
        } 
    } 
    を返す 
}

最終警告:

  • 総カバレッジが等しいときのhashCodeをオーバーライドします。
  • equalsメソッドを聞かせするには余りにもスマートにしようとしないでください。
  • 反対しないオブジェクトは、他のタイプを代用宣言に等しいです。

  に強制されない限り要するに、簡単に、等号を上書きしません。多くの場合、それは正確に何をしたい達成Objectから継承されますので。

  カバレッジがメソッドと等しい場合、このクラスのすべてのキー・フィールドを比較するとequals 5契約の条項の遵守を確保することを確認してください。

 

11 節:カバレッジが等しい常にhashCodeをカバー

  オーバーライドが等しい各クラスのメソッドでは、hashCodeメソッドを書き換えする必要があります。
  そうしない場合は、あなたのクラスは、一般的な慣例のhashCodeに違反する、とこれは、このようなHashMapのとHashSetの中で動作するように設定されなくなります。
 

  コード規則の内容をオブジェクト:

  • 比較は任意の情報を変更しない方法と等しい場合は、アプリケーションの実行の過程では、常に同じ値を返す必要があり、オブジェクトのhashCodeメソッドの呼び出しを繰り返しました。値が他のアプリケーションプログラムからアプリケーションに返されると一致しない場合があります。
  • 等号に従って二つのオブジェクト(Object)メソッドは、比較的等しい場合、2つのオブジェクトのハッシュコードを呼び出すと同じ整数の結果を生成しなければなりません。
  • 2つのオブジェクトが比較等しい(オブジェクト)の方法に従って等しくない場合は、各オブジェクトにコールハッシュコードが異なる結果を生成しなければならない必要はありません。のハッシュテーブルの性能(ハッシュ・テーブル)を改善することができる等しくないオブジェクトに対して異なる結果を生成します。

    同じオブジェクトが等しいハッシュコード(ハッシュコード)を有していなければならない:ハッシュコード違反は、上述した第2の法令をカバーしていません。

  この方法は、不均等なハッシュコードを生成する傾向が良いハッシュは不等の一例です。

  理想的には、ハッシュコードは、範囲のintセット不等インスタンスハッシュメソッド内で一様に割り当てられました。この理想的な状況を達成するために困難な場合があります。

 簡単な手順:
  1.最初のオブジェクトに初期化し、int型の結果の変数を宣言し、上記計算ステップ2.Aに記載されているように、ハッシュコードCの重要な特性です。
  オブジェクトfの残りの重要な特性のために2は、次のようにします
    Aは、ハッシュコードC :. Fの算出された属性int型である
      。IプロパティはType.hashCode(F)メソッドを使用して計算プリミティブ型である場合、対応するラッパークラスF請求型クラス属性。
      II。プロパティは、オブジェクト参照、および再帰的に再帰的hashCodeメソッドを呼び出して、呼び出し等しいこのクラスのプロパティを比較するにはequalsメソッドがある場合。

          このフィールドのあなたは、より複雑な比較が必要な場合は、コンピューティング「パラダイム」(標準的な表現)、とhashCodeパラダイムに呼び出します。

          このフィールドが空の場合は、0(他の定数を使用してもよいが、通常は0を示します)。
      III。プロパティは、配列要素の各々の、配列Fの場合独立性として重要です。

          配列の要素が重要でない場合は、定数を使用し、それがゼロに最善ではありません。すべての要素が非常に重要である場合は、をArrays.hashCodeメソッドを使用します。
    。ステップB計算されたハッシュコードcの2.Aは、以下の結果にマージ:結果=結果+ C * 31であり;
  (3)戻り結果値。

例:

// 一般的なhashCodeメソッド 
@Override 公共 int型のハッシュコード(){
     int型の結果= Short.hashCode(areaCode)。
    結果 = 31 *結果+ Short.hashCode(接頭辞)。
    結果 = 31 *結果+ Short.hashCode(LINENUM)。
    戻り値の結果; 
}

  検証が終わった後、自問してみてください「と等しいインスタンスが等しいハッシュコードを持っています。」

  要するに、カバレッジがのhashCodeをオーバーライドする必要がありequalsメソッドをいつでも、そうでないプログラムが正しく動作しません。
  また、自動入力値(グーグル)を利用手で書かなくても、equalsメソッドおよびhashCodeメソッドを生成することができる、あなたは省略テストすることができます。IDEの部分は、同様の機能部品を提供しています。

 

12 ルール:常にのtoStringをカバー

  良い読めるのtoStringの実装を提供することは、より簡単にデバッグするシステムのこのクラスを利用することができます。
  実際の応用では、toStringメソッドは、関心の対象に含まれるすべての情報を返す必要があります。指定された形式かどうかは、それが明確に文書であなたの意図を示す必要があります。
  静的クラスのツールでtoStringメソッドを書くとき、あなたはほとんどの列挙型のtoStringメソッドを記述していない意味がありません。
  Googleのオープンソース自動入力値toStringメソッドはあなたのために生成されます。

  要するに、我々はすでにスーパークラスに行っていない限り、あなたは書くインスタンス化することができるのtoStringオブジェクトは、各クラスで達成上書きしたいです。

  これは、デバッグするクラスの利用が容易になります。toStringメソッドは、オブジェクト、便利な説明について簡潔に返す必要があります。

 

13 バー:慎重にカバークローン

  Cloneableインタフェースオブジェクトはそのようなオブジェクトのクローニング(クローン)を示すことができ、インターフェースなどの目的です。
  Cloneableインタフェースクラスは、公開cloneメソッドへの適切な機能を提供するために実装されています。

  あなたはクラスのCloneableインタフェースを実装すると仮定し、その親クラスは行儀クローン方法を提供します。

  最初のコールsuper.clone。得られたオブジェクトは、元の完全に機能的なレプリカであろう。あなたのクラス内で宣言されるすべてのプロパティには、元のプロパティの値が同じになります。

  オブジェクトは、元の値または不変オブジェクトへの参照が含まれている場合、各属性は、リターンは、あなたが、この場合には、それ以上の処理を必要としないものをちょうどかもしれません。(浅いコピー)
 

  不変クラスは、クローン方法を提供することはありません。
  変更可能なオブジェクトを含むクローンシンプルオブジェクトならば、実装は壊滅的なの前面に表示することができます。

  例:

ublicのクラススタック{ 

    プライベートオブジェクトは、[]の要素。
    プライベート int型のサイズ= 0 ;
    プライベート 静的 最終 int型 = 16 DEFAULT_INITIAL_CAPACITY 

    パブリックスタック(){
         この .elements = 新しいオブジェクト[DEFAULT_INITIAL_CAPACITY]。
    } 

    公共 ボイドプッシュ(オブジェクトE){ 
        ensureCapacity()。
        要素【サイズ ++] = E。
    } 

    パブリックオブジェクトポップ(){
         場合(サイズ== 0 スロー 新しいですEmptyStackException(); 
        オブジェクトの結果 =要素[ - サイズ]。

        要素[サイズ] = NULL ; // 時代遅れ参照排除
        リターン結果を、
    } 

    // 1つ以上の要素のためのスペースを確保してください。
    プライベート ボイドensureCapacity(){
         場合(elements.length == サイズ)
            の要素 = Arrays.copyOf(要素、2 *のサイズ+ 1 )。
    } 
}

  唯一の方法は、クローンsuper.cloneに戻る場合、上記所望のクローンの例としては、作製することができる()オブジェクトを呼び出し、そのサイズ属性に正しい値が得られたスタックインスタンス

  しかし、元の基準要素プロパティスタックとして同じアレイ。元の制約条件の変更の例には、クローンを破壊する、およびその逆。

  あなたはすぐにあなたのプログラムが無意味な結果を生成、またはNullPointerExceptionがスローされることがわかります。
 

  実際には、cloneメソッドは、別のコンストラクタがあり、あなたはそれが元のオブジェクトに傷つけていないことを確認し、オブジェクトをクローン化することによって作成された適切な制約を確認する必要があります。
 再帰的に呼び出さアレイにおける上記要素の例は、クローン:

// 可変状態への参照を持つクラスのCloneメソッド 
@Override 公共スタッククローンは、(){
     しようと{ 
        スタックの結果 =(スタック)スーパー.clone(); 
        result.elements = elements.clone()。
        戻り値の結果; 
    } キャッチ(CloneNotSupportedException電子){
         スロー 新しい)(てAssertionErrorを、
    } 
}

  配列のクローン返され、タイプおよび配列タイプのアレイ上の通話は、これは、配列をコピーするための最良の習慣です、同じコンパイル時にクローン化されます。

  要素のプロパティが最終であれば、従来のソリューションは、クローンは、属性を禁止することであろうことから、動作しません新しい値が割り当てられます。

  これは根本的な問題である:通常の使用Cloneableをアーキテクチャのシーケンスと同じ最終的な属性参照変数オブジェクトは互換性がありません。
 

  ただ、クローンメソッドは常に十分ではありません再帰的に呼び出します。

  例えば、クラス・ハッシュ・バケットは、各ハッシュキーを渡す点の配列を含んでいる - 最初のリストの値は、単独でリンクされたリストです。

  唯一のクローンハッシュアレイ場合が、元のオブジェクトとして配列リファレンスリストとして、そして元のオブジェクト不明挙動をクローニングしやすいです。すべてのコピーは個別にリストし、各バケットをリンクする必要があります。

  要するに、すべて実現Cloneableをパブリッククラスがcloneメソッドをオーバーライドする必要があり、このメソッドの戻り値の型は、クラス自体です。

  この方法は、最初の修復を必要としている任意のプロパティを修復、その後、super.cloneを呼び出す必要があります。

  通常、これはオブジェクトの原点を置き換えるために、新しいオブジェクトを参照して、変数オブジェクトの内部「深層構造」を含むすべてのファイルをコピーすることを意味します。

  これらの内部コピーは通常、再帰呼び出しすることによって達成することができますが、クローンが、これは必ずしも最善の方法ではありません。

  クラスは、プリミティブ型または不変オブジェクトへの参照のみが含まれている場合、それは修復が必要なプロパティの場合ではないかもしれません。

  このルールには例外がありますが、例えば、シリアル番号を表すか、またはその他の固有の属性のIDも補正する必要があり、実質的に均一または不変タイプです。

  コピーコンストラクタ(コピーコンストラクタ)植物またはコピー(コピー工場)ときより良い方法のオブジェクトのコピー。

// コピーコンストラクタ
パブリックヤム(ヤムヤム){...}。
// コピー工場
パブリック 静的廉のnewInstance(ヤムヤム){...};

  要するに、考慮にCloneableインタフェースに関連付けられているすべての問題を取って、新しいインターフェイスがそれを継承するべきではない、新しい拡張可能なクラスがそれを実装するべきではありません。

  しかし害finalクラスにCloneableインタフェースを実装しますが、のみまれに(エントリー67)正当化される、ビューのパフォーマンスの最適化ポイントとしてみなされるべきです。

  典型的には、コピー機能は、好ましくは、コンストラクタや工場によって提供します。この規則に対する注目すべき例外は、好ましくは、クローン方法により再生される配列です。

 

第14条:Comparableインタフェースを実装を検討

  この章で説明する他の方法とは異なり、compareToメソッドは、Objectクラスで宣言されていませんでした。

  代わりに、それが唯一の方法Comparableインタフェースです。Comparableインタフェースは、それが自然な順序(自然順序付けを)持っているクラスのインスタンスによって実装します。

  Comparableインタフェースを実装することで、あなたは、一般的なアルゴリズムと相互運用するには、このインターフェイスのすべての依存実装のコレクションを使用してクラスを作ることができます。

  ほとんどすべてのクラスと列挙型(項目34)の全ての値のJavaプラットフォームライブラリは、Comparableインタフェースを実装します。

  あなたは大きな値クラスの自然順序(例えば、アルファベット順、数字順や日付順に)書いている場合、インターフェイスはComparableを実装する必要があります。

パブリック インターフェース匹敵<T> {
     int型のcompareTo(T T)。
}

  指定されたオブジェクトとこのオブジェクトはソート比較されます。戻り値が負の整数、0または正の整数であってもよく、オブジェクトに対応する指定されたオブジェクトよりも、より少ない以上です。
  異なるタイプのオブジェクトを比較する際に異なるタイプのオブジェクト間のcompareToはClassCastExceptionがスロー、比較することはできません。

  compareToメソッドは、equalsと矛盾しているBigDecimalクラスを、考えてみましょう。

  あなたは空のHashSetのインスタンスを作成し、新しいBigDecimalを(「1.0」)と新しいのBigDecimal(「1.00」)を追加した場合、コレクションは、2つの要素が含まれています

  equalsメソッドと比較して、BigDecimalのインスタンスの二組に追加ので等しくありません。

  もし代わりに同じ手順を使用して、HashSetのTreeSetののcompareToメソッドを使用して比較二つのBigDecimalインスタンスが等しいしかし、セットは、唯一つの要素を含むであろう。

  ジャワ7において、静的比較方法は、すべてのパッケージのJavaクラスに追加されます。プロセスのcompareToに関係演算子を使って<と>退屈でエラーが発生しやすいが、もはや推奨されません。

  コンパレータインタフェースでJava 8の方法コンパレータのセットを提供し、コンパレータが円滑に構築することができます。

  それはいくつかのパフォーマンスを犠牲にしますが、多くのプログラマは、このアプローチの単純さを好みます。Javaを使用して、静的インポートを考慮すると、このメソッドを使用すると、コンパレータは、静的メソッドによって簡単な名前に参照することができます。

// コンパレータ構築方法に匹敵する
プライベート 静的 最終コンパレータ<のPhoneNumber>コンパレータ= 
        comparingInt((のPhoneNumber PN) - > pn.areaCode)
            .thenComparingInt(PN - > pn.prefix)
            .thenComparingInt(PN - > pn.lineNum)。
公共 のint のcompareTo(のPhoneNumber PN){
     戻り COMPARATOR.compare(この、PN)を、
}

 

おすすめ

転載: www.cnblogs.com/fyql/p/11401798.html