hashCode()
メソッドはJavaでどのような値を返しますか?
オブジェクトのメモリ参照であると読みました...のハッシュ値new Integer(1)
は1です。のハッシュ値String("a")
は97です。
私は混乱しています:それはASCIIですか、それともどのような種類の値ですか?
によって返される値はhashCode()
、オブジェクトのメモリアドレスであることが保証されているわけではありません。クラスでの実装はわかりませんが、Object
ほとんどのクラスはhashCode()
、意味的に同等である(ただし、同じインスタンスではない)2つのインスタンスが同じ値にハッシュされるようにオーバーライドすることに注意してください。hashCode
これは、クラスがSetなど、との整合性に依存する別のデータ構造内で使用される可能性がある場合に特に重要ですequals
。
何hashCode()
があっても、オブジェクトのインスタンスを一意に識別するものはありません。基になるポインタに基づくハッシュコードが必要な場合(Sunの実装など)、-を使用します。これにより、オーバーライドされているかどうかに関係なくSystem.identityHashCode()
、デフォルトのメソッドに委任されます。hashCode
それでも、System.identityHashCode()
複数のオブジェクトに対して同じハッシュを返すこともできます。説明についてはコメントを参照してください。ただし、同じが2つ見つかるまでオブジェクトを継続的に生成するプログラムの例を次に示しますSystem.identityHashCode()
。System.identityHashCode()
これを実行すると、平均して約86,000のLongラッパーオブジェクト(およびキーの整数ラッパー)をマップに追加した後、一致する2つのがすぐに見つかります。
public static void main(String[] args) {
Map<Integer,Long> map = new HashMap<>();
Random generator = new Random();
Collection<Integer> counts = new LinkedList<>();
Long object = generator.nextLong();
// We use the identityHashCode as the key into the map
// This makes it easier to check if any other objects
// have the same key.
int hash = System.identityHashCode(object);
while (!map.containsKey(hash)) {
map.put(hash, object);
object = generator.nextLong();
hash = System.identityHashCode(object);
}
System.out.println("Identical maps for size: " + map.size());
System.out.println("First object value: " + object);
System.out.println("Second object value: " + map.get(hash));
System.out.println("First object identityHash: " + System.identityHashCode(object));
System.out.println("Second object identityHash: " + System.identityHashCode(map.get(hash)));
}
出力例:
Identical maps for size: 105822
First object value: 7446391633043190962
Second object value: -8143651927768852586
First object identityHash: 2134400190
Second object identityHash: 2134400190
ハッシュコードは、呼び出されたオブジェクトの状態を表す整数値です。そのため、 1に設定すると、ハッシュコードとその値は同じであるInteger
ため、「1」のハッシュコードが返されます。Integer's
文字のハッシュコードは、ASCII文字コードと同じです。hashCode
カスタムタイプを作成する場合は、現在のインスタンスの状態を最もよく表す適切な実装を作成する責任があります。
それらがどのように実装されているかを知りたい場合は、ソースを読むことをお勧めします。+ IDEを使用している場合は、関心のあるメソッドを+実行して、メソッドがどのように実装されているかを確認できます。それができない場合は、ソースをグーグルで検索できます。
たとえば、Integer.hashCode()は次のように実装されます。
public int hashCode() {
return value;
}
およびString.hashCode()
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len; i++) {
h = 31*h + val[off++];
}
hash = h;
}
return h;
}
このhashCode()
メソッドは、オブジェクトを識別するためによく使用されます。Object
実装はオブジェクトのポインタ(実際のポインタではなく、一意のIDなど)を返すと思います。ただし、ほとんどのクラスはメソッドをオーバーライドします。String
クラスのように。2つのStringオブジェクトには同じポインターはありませんが、同じです。
new String("a").hashCode() == new String("a").hashCode()
の最も一般的な用途hashCode()
はHashtable
、HashSet
などです。
編集:(最近の反対票のため、JVMパラメーターについて読んだ記事に基づいています)
JVMパラメータ-XX:hashCode
を使用すると、hashCodeの計算方法を変更できます(Java Specialists'NewsletterのIssue222を参照)。
HashCode == 0:オブジェクトが見つかったメモリ内の場所とは関係なく、単に乱数を返します。私の知る限り、シードのグローバルな読み取り/書き込みは、多数のプロセッサを搭載したシステムには最適ではありません。
HashCode == 1:ハッシュコード値をカウントアップします。どの値で開始するかはわかりませんが、かなり高いようです。
HashCode == 2:常にまったく同じIDハッシュコード1を返します。これは、オブジェクトIDに依存するコードをテストするために使用できます。上記の例でJavaChampionTestがKirkのURLを返した理由は、すべてのオブジェクトが同じハッシュコードを返していたためです。
HashCode == 3:ゼロから始めてハッシュコード値をカウントアップします。スレッドセーフではないように見えるため、複数のスレッドが同じハッシュコードでオブジェクトを生成する可能性があります。
HashCode == 4:これは、オブジェクトが作成されたメモリの場所と何らかの関係があるようです。
HashCode> = 5:これはJava 8のデフォルトのアルゴリズムであり、スレッドごとのシードがあります。Marsagliaのxor-shiftスキームを使用して、疑似乱数を生成します。
オブジェクトのメモリ参照だと読みました。
Object.hashCode()
約14年前にメモリアドレスを返すために使用された番号。それ以来ではありません。
値のタイプは何ですか
それが何であるかは、あなたが話しているクラスと、それが `Object.hashCode()をオーバーライドしたかどうかに完全に依存します。
OpenJDKソース(JDK8)から:
デフォルトの5を使用して、ハッシュコードを生成します。
product(intx, hashCode, 5,
"(Unstable) select hashCode generation algorithm")
いくつかの定数データと、スレッドごとに開始されたシードを使用してランダムに生成された数値:
// thread-specific hashCode stream generator state - Marsaglia shift-xor form
_hashStateX = os::random() ;
_hashStateY = 842502087 ;
_hashStateZ = 0x8767 ; // (int)(3579807591LL & 0xffff) ;
_hashStateW = 273326509 ;
次に、この関数はhashCode(上記で指定されたデフォルトは5)を作成します。
static inline intptr_t get_next_hash(Thread * Self, oop obj) {
intptr_t value = 0 ;
if (hashCode == 0) {
// This form uses an unguarded global Park-Miller RNG,
// so it's possible for two threads to race and generate the same RNG.
// On MP system we'll have lots of RW access to a global, so the
// mechanism induces lots of coherency traffic.
value = os::random() ;
} else
if (hashCode == 1) {
// This variation has the property of being stable (idempotent)
// between STW operations. This can be useful in some of the 1-0
// synchronization schemes.
intptr_t addrBits = cast_from_oop<intptr_t>(obj) >> 3 ;
value = addrBits ^ (addrBits >> 5) ^ GVars.stwRandom ;
} else
if (hashCode == 2) {
value = 1 ; // for sensitivity testing
} else
if (hashCode == 3) {
value = ++GVars.hcSequence ;
} else
if (hashCode == 4) {
value = cast_from_oop<intptr_t>(obj) ;
} else {
// Marsaglia's xor-shift scheme with thread-specific state
// This is probably the best overall implementation -- we'll
// likely make this the default in future releases.
unsigned t = Self->_hashStateX ;
t ^= (t << 11) ;
Self->_hashStateX = Self->_hashStateY ;
Self->_hashStateY = Self->_hashStateZ ;
Self->_hashStateZ = Self->_hashStateW ;
unsigned v = Self->_hashStateW ;
v = (v ^ (v >> 19)) ^ (t ^ (t >> 8)) ;
Self->_hashStateW = v ;
value = v ;
}
value &= markOopDesc::hash_mask;
if (value == 0) value = 0xBAD ;
assert (value != markOopDesc::no_hash, "invariant") ;
TEVENT (hashCode: GENERATE) ;
return value;
}
したがって、少なくともJDK8では、デフォルトがランダムスレッド固有に設定されていることがわかります。
定義:String hashCode()メソッドは、Stringのハッシュコード値を整数として返します。
構文: public int hashCode()
ハッシュコードは、以下の式を使用して計算されます
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
where:
s is ith character in the string
n is length of the string
^ is exponential operand
例: たとえば、文字列「abc」のハッシュコードを計算する場合は、以下の詳細があります
s[] = {'a', 'b', 'c'}
n = 3
したがって、ハッシュコード値は次のように計算されます。
s[0]*31^(2) + s[1]*31^1 + s[2]
= a*31^2 + b*31^1 + c*31^0
= (ASCII value of a = 97, b = 98 and c = 99)
= 97*961 + 98*31 + 99
= 93217 + 3038 + 99
= 96354
したがって、「abc」のハッシュコード値は96354です。
Object.hashCode()は、メモリが正しく機能する場合(JavaDocでjava.lang.Objectを確認)、実装に依存し、オブジェクトに応じて変化します(Sun JVMは、オブジェクトへの参照の値から値を取得します) )。
重要なオブジェクトを実装していて、それらをHashMapまたはHashSetに正しく格納したい場合は、hashCode()とequals()をオーバーライドする必要があることに注意してください。hashCode()は好きなことを行うことができます(完全に合法ですが、1を返すのは最適ではありません)が、equals()メソッドがtrueを返す場合、両方のオブジェクトのhashCode()によって返される値が等しいことが重要です。
hashCode()とequals()の混乱と理解の欠如は、バグの大きな原因です。Object.hashCode()およびObject.equals()のJavaDocsに完全に精通していることを確認してください。また、費やした時間がそれ自体で支払われることを保証します。
Javadocから:
合理的に実用的である限り、クラスObjectによって定義されたhashCodeメソッドは、個別のオブジェクトに対して個別の整数を返します。(これは通常、オブジェクトの内部アドレスを整数に変換することによって実装されますが、この実装手法はJava™プログラミング言語では必要ありません。)
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--
誰もこれについて言及していないことに驚いていますが、Object
クラス以外の人にとって最初のアクションは、多くのクラスのソースコードを読み取ることですが.hashcode()
、Object
その場合、JVMに応じていくつかの異なる興味深いことが起こる可能性があります。実装。Object.hashcode()
への呼び出しSystem.identityHashcode(object)
。
実際、メモリ内でオブジェクトアドレスを使用することは古代の歴史ですが、多くの人は、この動作を制御できること、およびNが[0-5]の数値であるObject.hashcode()
jvm引数を介してどのように計算されるかを認識していません。-XX:hashCode=N
0 – Park-Miller RNG (default, blocking)
1 – f(address, global_statement)
2 – constant 1
3 – serial counter
4 – object address
5 – Thread-local Xorshift
アプリケーションによっては、が呼び出されたときに予期しないパフォーマンスヒット.hashcode()
が発生する場合があります。その場合、グローバル状態やブロックを共有するアルゴリズムの1つを使用している可能性があります。