火曜日にJavaが有効になります!`hashCode`規約に準拠する

今日のトピックは先週のトピックと一致しています。今週はhashCode関数について話します。先週説明した関数と同様に、このメソッドにもコントラクトがありますが、比較的単純ですが、それに従う必要があります。シグネチャと同様に、パラメータをとらず、整数を返します。だから私たちは契約に署名しましょう:

  • オブジェクトが変更されていない場合、関数から返される値は変更されないままである必要があります。2つのオブジェクトが実際に等しい場合、それらのハッシュコードは同じでなければなりません。(これは必須ではありません。)2つのオブジェクトが実際には等しくない場合、異なるハッシュコード値を持つ必要はありません。

このようにして、ハッシュコードが等価性に密接に関連していることがわかります。2番目の要件は、最も壊れた要件です。ハッシュコード関数を実装しない場合、2つの実質的に等価なオブジェクトは、関数から返される同じ値を持たない可能性があります。それでは、例を見てみましょう:

Map<Address, String> addressBook = new HashMap<>();
addressBook.put(new Address("123","Foggy Lane" "Made Up City", "USA"), "James");
addressBook.get(new Address("123","Foggy Lane" "Made Up City", "USA"));

上記の例では、3行目で「James」が返されることが予想されますが、ハッシュコード関数が誤って記述されている場合は、null値が返されます。

したがって、最も単純な正当なハッシュコード関数を記述してみましょう。

@Override
public int hashCode() {
  return 42;
}

はい、契約によると、これは完全に有効なハッシュコード関数です。同じオブジェクトで複数回呼び出された場合、常に同じものを返します。機能的に同等のオブジェクトの場合、同じ値を返します。2つの機能的に同等のオブジェクトの場合、同じハッシュコードを返します。 。ただし、コントラクトに準拠していても、返される値は変更されません。これはひどい考えであり、パフォーマンスが大幅に低下する可能性があります。たとえば、パフォーマンスに関して、上記のハッシュコード関数はHashMapをリンクリストに効果的に変換します。

もっと良い方法があるに違いありません。効果的なJavaは、確実なハッシュコード関数を作成する方法を提供します。

  1. ステップ2で計算されるように、整数の命名結果を宣言し、それをオブジェクトの最初の有効なフィールドの値に初期化します(「有効なフィールド」とは、2つのオブジェクトが等しいときに決定に参加するフィールドを指します)。残りのすべての重要なフィールドについて、この整数フィールドのハッシュコードを次のように計算します。フィールドが元のフィールドである場合は、フィールドのボックスバージョンを使用して、hashCode関数を計算します。例:Double.hashCode(値)フィールドがオブジェクト参照の場合、そのオブジェクトのhashCode関数で整数を呼び出します。nullの場合、配列の場合は値0を使用し、重要な各要素を個別のフィールドとして扱うか、すべてが重要な場合はArrays.hashCodeを使用します。次のように、計算したハッシュコードと結果を組み合わせます。result= 31 * result + newFieldHashcode return result

上記のアルゴリズムに正しく従えば、信頼できるハッシュコードを計算する必要があります。このアルゴリズムの利点は、操作の順序が重要であるため、より適切な割り当てを実現できることです。31を掛けることは、奇数の素数であるため、適切です。奇数は整数のオーバーフローに役立ちますが、素数は素数が優れているためです。現実には、標準になっているように思えます。新しいアドレスのhashCode関数を見てみましょう。

@Override
public int hashCode() {
  int result = streetAddress.hashCode();
  result = 31 * result + road.hashCode();
  result = 31 * result + country.hashCode();
  return result;
}

かなりシンプルですが効果的です。これらの関数を書く簡単な方法はありますか?もちろんです。例は、Objects.hashCode(significantField1、IdentificationField2、...)の使用です。1行のhashCode関数であるため、非常に優れています。欠点は、そのパフォーマンスが前の例よりも悪いことです。しかし、私はロンボクのようなものを使用するのが最善の方法だと思います。Lombokは、@ EqualsAndHashCodeアノテーションを実装しました。Lombokのメンテナーは、hashCodeに強制的に等しいことを非常に喜んでいます。

最後に、覚えておくべきいくつかのハッシュコードについて議論しましょう:

  • 等しい値を上書きする場合は、常にハッシュコードを上書きして、計算の一部としてハッシュコードと等しい使用中のすべての値を含めます。ハッシュコードの計算方法を関数の外部で共有しないでください。不必要にサブパー実装に結び付く可能性があります。

から:https://dev.to//kylec32/effective-java-tuesday-obey-the-hashcode-contract-3onl

元の記事を公開0件 ・いい ね0件 訪問634

おすすめ

転載: blog.csdn.net/cunxiedian8614/article/details/105691244