1つの同じオブジェクト、特にstring
または任意のプリミティブ型または非常に単純な型(struct
)の異なる値を生成する.GetHashCode()
別のマシンで呼び出されたときのメソッド?
例えば、"Hello World".GetHashCode()
異なるマシンで異なる値を生成するため。私は主にC#.NETを求めていますが、これはJavaや他の言語にも当てはまると思いますか。
編集する
以下の答えとコメントから指摘されるように、それは私に知られています.GetHashCode()
することができますオーバーライドそして、それが異なるバージョンのフレームワーク間で生成される結果についての保証はありません。したがって、私は単純型を念頭に置いていることを明確にすることが重要です。GetHashCode()
私はすべてのマシンで同じバージョンのフレームワークを使用しています。
短い答え:はい。
しかし、短い答えは面白くないのですか?
実装しているときGetHashCode()
次の保証をする必要があります。
いつ
GetHashCode()
このAppドメインでは、これと等しいと見なされるべきである別のオブジェクトで呼び出されると、同じ値が返されます。
それでおしまい。実際にやらなければならないことがいくつかあります(可能な限り等しくないオブジェクトでビットを分散させますが、そもそもハッシュ化のすべての利点よりも優先されるのであまり時間をかけないでください)。そうしなければ吸いますが、実際には壊れません。あなたがそれほど遠くに行かなければそれは壊れるでしょう。
dict[myObj] = 3;
int x = dict[myObj];//KeyNotFoundException
はい。実装している場合GetHashCode()
なぜ私はそれより先に進むのでしょうか、そしてなぜ私はしないのですか?
まず、どうして私は違うのでしょうか。
多分それはアセンブリのわずかに異なるバージョンであり、私はビルドの間に改良した(あるいは少なくとも試みた)。
たぶん1つは32ビット、もう1つは64ビットで、効率をよくするためにそれぞれ異なるアルゴリズムを選択しました(特にコレクションや文字列などのオブジェクトをハッシュする場合はこれまでにないことです)。 。
多分私は "等しい"オブジェクトを構成するものを決定する際に検討することにしたいくつかの要素は、このような方法でシステムごとに異なります。
たぶん私は、同僚が私のハッシュコードに誤って依存しているような場合を捉えるために、実際に故意に異なるビルドで異なるシードを導入するかもしれません! (私はMSが彼らの実装でこれをすると聞きましたstring.GetHashCode()
しかし、私がそれを信頼できる情報源から聞いたのか、それとも信頼できる情報源から聞いたのかを思い出すことはできません。
しかし、主に、それは最初の2つの理由のうちの1つでしょう。
では、どうして私はそのような保証をしなければならないのでしょうか。
たぶん私がそうするならば、それは偶然によるでしょう。要素が単一の整数idだけに基づいて等しいかどうかを比較できる場合は、それが私のハッシュコードとして使用されることになります。それ以外のものは、あまり良くないハッシュのためにはもっと仕事になるでしょう。これを変更する可能性は低いので、変更するかもしれません。
私がそうするかもしれないもう一つの理由は、私がその保証を自分が欲しいということです。私がそれを提供することができないと言うことは何もありません、私がする必要がないということだけ。
さて、実用的なものに行きましょう。機械に依存しない保証が必要な場合があります。あなたが反対のことを望んでいるかもしれない場合があります。
まず、論理を確認してください。衝突に対処できますか?それでは始めましょう。
それがあなた自身のクラスであれば、そのような保証を提供するように実装し、それを文書化すれば完了です。
それがあなたのクラスではない場合は、次に実装してくださいIEqualityComparer<T>
それを提供するような方法で。例えば:
public class ConsistentGuaranteedComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return x == y;
}
public int GetHashCode(string obj)
{
if(obj == null)
return 0;
int hash = obj.Length;
for(int i = 0; i != obj.Length; ++i)
hash = (hash << 5) - hash + obj[i];
return hash;
}
}
それから組み込みのハッシュコードの代わりにこれを使ってください。
私たちが反対を望んでいるかもしれない興味深いケースがあります。ハッシュしている文字列のセットを制御できれば、同じハッシュコードを持つ一連の文字列を選ぶことができます。あなたのハッシュベースのコレクションのパフォーマンスは、最悪のケースに襲われ、かなり残酷なものになるでしょう。たぶん私はあなたがそれに対処することができるより速くこれをし続けることができるので、それはサービス拒否攻撃になることができます。これが起こるケースはあまりありませんが、重要なのは私が送るXML文書を扱っていて、いくつかの要素を除外できない場合です(多くのフォーマットはそれらの中の要素の自由を可能にします)。そうしてNameTable
あなたのパーサーの中は怪我をするでしょう。この場合、毎回新しいハッシュメカニズムを作成します。
public class RandomComparer : IEqualityComparer<string>
{
private int hashSeed = Environment.TickCount;
public bool Equals(string x, string y)
{
return x == y;
}
public int GetHashCode(string obj)
{
if(obj == null)
return 0;
int hash = hashSeed + obj.Length;
for(int i = 0; i != obj.Length; ++i)
hash = hash << 5 - hash + obj[i];
hash += (hash << 15) ^ 0xffffcd7d;
hash ^= (hash >>> 10);
hash += (hash << 3);
hash ^= (hash >>> 6);
hash += (hash << 2) + (hash << 14);
return hash ^ (hash >>> 16)
}
}
これは特定の用途では一貫していますが、用途ごとでは一貫していません。そのため、攻撃者は入力を強制的にDoSsedにすることはできません。ちなみにNameTable
を使用しないIEqualityComparer<T>
必要でない限り、文字列を構築せずにインデックスと長さを持つchar配列を扱いたいのですが、似たようなことをします。
ちなみに、Javaではハッシュコードはstring
が指定されて変更されることはありませんが、これは他のクラスには当てはまりません。
編集:アプローチの全体的な質についていくつかの研究を行ったことConsistentGuaranteedComparer
上記のように、私は自分の答えにそのようなアルゴリズムがあることにもう満足していません。それは概念を説明するのに役立ちますが、それは人が好むかもしれないほど良いディストリビューションを持っていません。もちろん、そのようなことをすでに実装しているのであれば、保証を破ることなしにそれを変更することはできません。この研究の後に書かれた私のこの図書館次のように:
public class ConsistentGuaranteedComparer : IEqualityComparer<string>
{
public bool Equals(string x, string y)
{
return x == y;
}
public int GetHashCode(string obj)
{
return obj.SpookyHash32();
}
}
それはRandomComparer
上記はそれほど悪くはありませんが、改善することもできます。
public class RandomComparer : IEqualityComparer<string>
{
private int hashSeed = Environment.TickCount;
public bool Equals(string x, string y)
{
return x == y;
}
public int GetHashCode(string obj)
{
return obj.SpookyHash32(hashSeed);
}
}
あるいは、予測がさらに難しい場合は、
public class RandomComparer : IEqualityComparer<string>
{
private long seed0 = Environment.TickCount;
private long seed1 = DateTime.Now.Ticks;
public bool Equals(string x, string y)
{
return x == y;
}
public int GetHashCode(string obj)
{
return obj.SpookyHash128(seed0, seed1).GetHashCode();
}
}
string.GetHashCode()
...".NETソースが利用可能になりました今信頼できる情報源を持っていますそれは彼らが実際にいくつかのビルドでランダムハッシュコードを使用していることを示していますFEATURE_RANDOMIZED_STRING_HASHING
ビルド変数が設定されています。また、DEBUG
彼らも作るhash1 ^= ThisAssembly.DailyBuildNumber;
ハッシュ値を永続化しようとするような愚かなことをしている人がいないことを確認するため - Scott Chamberlain
それ意志実行が異なる同じマシンでも、結果が異なります。
そのため、基本的には(実際に使用されている)使用中に何かをチェックすることができます。現在プログラムの実行が、その後それに対して何かをチェックするためにそれを格納するためには意味がありません。あなたが得た数が生成される原因ランタイム。
編集
文字列の特定のケースでは、マシンのアーキテクチャが異なる場合を除いて、異なるマシンでも同じ結果が得られます。