in Java 7があります
_o.hashCode();
Objects.hashCode(o);
Objects.hash(o);
_
最初の2つはヌルポイントチェックとほぼ同じですが、最後の2つは何ですか?
単一のオブジェクト参照が提供される場合、戻り値はそのオブジェクト参照のハッシュコードと等しくなりません。
何故ですか?つまり、同じことを行う3つのメソッドは必要ありませんが、それは理解できますが、なぜObjects.hash()
が必要なのでしょうか?いつ使用するのを選択しましたか?
hashCode
および hash
のドキュメントを参照してください。 hash
は_Object...
_を取り、hashCode
はObject
を取ります。例は次のとおりです。
_@Override public int hashCode() {
return Objects.hash(x, y, z);
}
_
Objects.hash(Object... values)
は、オブジェクトのシーケンスのハッシュが必要な場合に使用する必要があります。独自のhashCode
メソッドを定義し、オブジェクトのIDを構成する複数の値に対して単純にコード化されたハッシュが必要な場合。Objects.hashCode(Object o)
は、オブジェクトがnullの場合にスローせずに、単一のオブジェクトのハッシュが必要な場合に使用する必要があります。Object::hashCode()
は、単一のオブジェクトのハッシュが必要な場合に使用する必要があり、オブジェクトがnullの場合は例外をスローします。hash(o)
とhashCode(o)
は必ずしも同じものを返さないことに注意してください!単一のオブジェクトに対して実行する場合は、おそらくhashCode
を使用する必要があります。
Objects.hashCode
_ユーティリティメソッド Objects.hashCode( Object o )
は、渡されたオブジェクトでhashCode
メソッドを呼び出すだけです。
では、なぜこの方法を発明または使用するのでしょうか?オブジェクトのhashCode
メソッドを自分で呼び出すだけではどうですか?
この方法には1つの利点があります:NULL
➙_0
_。ユーティリティメソッドはnullを許容します。
myObject
がNULL
であるObjects.hashCode( myObject )
を呼び出すと、ゼロ(0)が返されます。myObject
がNULL
であるときにmyObject.hashCode()
を呼び出すと、NullPointerException
引数がスローされます。ヌルを許容することが望ましいかどうかは、特定の状況でのあなた自身の判断に依存します。
Objects.hash
_ユーティリティメソッド Objects.hash( Object o , … )
は、別の目的を果たします。この方法には2つのフェーズがあります。
.hashCode
_を呼び出し、各結果を収集します。単一のオブジェクトObjects.hash( myObject )
を渡すと、最初に_myObject.hashCode
_が呼び出されて収集され、次にその単一項目コレクションのハッシュが計算されます。したがって、ハッシュの hash になります。
単一のオブジェクトをハッシュする場合、Objects.hashCode( myObject )
がObjects.hash( myObject )
とは異なる結果を返すことを理解することが重要です。事実上、2番目は最初の結果のハッシュを返します。
これらの2つのObjects
メソッドで採用されているアプローチのロジックは、それ自体が理にかなっています。
残念ながら、実際には、POJOでhashCode
およびそれに対応するequals
をオーバーライドするコードを記述するときに日常的に使用しようとする人にとっては、決定するために2度考えなければなりません。どちらを呼び出すか。
hashCode
(およびequals
)オーバーライドがクラスの単一のメンバーに基づいている場合は、Objects.hashCode( member )
を使用します。hashCode
(およびequals
)オーバーライドがクラスの複数の属性に基づいている場合は、Objects.hash( memberA , memberB , memberC )
を使用します。_@Override
public int hashCode() {
return this.member.hashCode() ; // Throws NullPointerException if member variable is null.
}
_
_@Override
public int hashCode() {
return Objects.hashCode( this.member ) ; // Returns zero (0) if `this.member` is NULL, rather than throwing exception.
}
_
_@Override
public int hashCode() {
return Objects.hash( this.memberA , this.memberB , this.memberC ) ; // Hashes the result of all the passed objects’ individual hash codes.
}
_
これらのさまざまな方法を非常に簡単にテストできます。
例として UUID
オブジェクトを使用してみましょう。 [〜#〜] uuid [〜#〜] (普遍的に一意の識別子)は128ビット値であり、特定の場合ビットには特定のセマンティクスがあります。
UUID
のOpenJDK実装は、128ビット値を64ビットlong
整数のペアとして内部的に表します。 。
同じ実装は_Object::equals
_および_Object::hashCode
_をオーバーライドして、その長い整数のペアに格納されているデータを調べます。 これら2つのメソッドのソースコード です。
_public boolean equals(Object obj) {
if ((null == obj) || (obj.getClass() != UUID.class))
return false;
UUID id = (UUID)obj;
return (mostSigBits == id.mostSigBits &&
leastSigBits == id.leastSigBits);
}
_
_public int hashCode() {
long hilo = mostSigBits ^ leastSigBits;
return ((int)(hilo >> 32)) ^ (int) hilo;
}
_
UUIDオブジェクトをインスタンス化します。
_UUID uuid = UUID.randomUUID();
_
ハッシュ値を計算します。
_int hash1 = uuid.hashCode();
int hash2 = Objects.hashCode( uuid ); // Result matches line above.
int hash3 = Objects.hash( uuid ); // Returns a hash of a hash.
int hash4 = Objects.hash( uuid.hashCode() ); // Result matches line above.
_
コンソールにダンプします。
_System.out.println( "uuid.toString(): " + uuid.toString() );
System.out.println( " 1/2 = " + hash1 + " | " + hash2 );
System.out.println( " 3/4 = " + hash3 + " | " + hash4 );
_
こちらをご覧ください コードはIdeOne.comでライブ実行 。
uuid.toString():401d88ff-c75d-4607-bb89-1f7a2c6963e1
1/2 = 278966883 | 278966883
3/4 = 278966914 | 278966914
ObjectのデフォルトのhashCode()は、オブジェクトのメモリアドレスを返します。したがって、次のクラスがある場合:
class Car {
String make;
String model;
int year;
public Car(String make, String model, int year) {
this.make = make;
this.model = model;
this.year = year;
}
}
次に、2つのオブジェクトを作成します。
Car car1 = new Car("Toyota", "Corolla", 2010);
Car car2 = new Car("Toyota", "Corolla", 2010);
car1.hashCode()はcar2.hashCode()とは異なります。これは、各オブジェクトが異なるメモリアドレスを持つためです。
Car1とcar2の両方が同じハッシュコードを返すようにするにはどうしますか?この場合、次のようにCarクラスのデフォルトのObject hashCode()メソッドをオーバーライドする必要があります。
@Override
public int hashCode() {
Object[] x = {model, make, Integer.valueOf(year)};
int hashArray = Arrays.hashCode(x);
return hashArray;
}
これにより、string.hashCode()は文字列の内容に基づいてhashCodeを計算し、Integer.hashCode()は整数値自体を返すため、car1.hashCode()はcar2.hashCode()と等しくなります。
Java 7では、Objects.hash(Object ... values)を使用できます。したがって、新しいCar hashCode()は次のようになります。
@Override
public int hashCode() {
return Objects.hash(model, make, year);
}
Objects.hash(Object ... values)は、Arrays.hashCodeを呼び出します。
最後に、Objects.hashCode(Object o)はnullチェックを行います。オブジェクトがnullの場合、0を返します。そうでない場合は、オブジェクトのhashCode()メソッドを呼び出します。