"Açık / kapalı konu" gri alanına girmek, ancak Oscar Reyes ile ilgili kafa karışıklığını gidermek için gerekli, HashMap'teki öğelerin sayısını azalttığı için daha fazla hash çarpışmasının iyi bir şey olduğunu öne sürüyor. Oscar'ın söylediklerini yanlış anlayabilirim, ancak tek kişi gibi görünmüyorum: kdgregory, delfuego, Nash0 ve sanırım hepimiz aynı (yanlış) anlayışı paylaşıyorum.
Oscar'ın aynı hashcode ile aynı sınıf hakkında söylediklerini anlarsam, HashMap'e belirli bir hashcode ile bir sınıfın yalnızca bir örneğinin eklenmesini öneriyor. Örneğin, karma kodu 1 olan bir SomeClass örneğine ve karma kodu 1 olan ikinci bir SomeClass örneğine sahipsem, yalnızca bir SomeClass örneği eklenir.
Http://pastebin.com/f20af40b9 adresindeki Java pastebin örneği , yukarıdakinin Oscar'ın önerdiği şeyi doğru bir şekilde özetlediğini gösteriyor gibi görünüyor.
Ne olursa olsun herhangi bir anlayış ya da yanlış anlama, ne olur aynı sınıfın farklı örnekleri do not o anahtarları eşit olup olmadığı belirlenmektedir olmayacağım kadar - aynı karma kodunun varsa HashMap içine sadece bir kez takılı olsun. Karma kod sözleşmesi, eşit nesnelerin aynı karma koduna sahip olmasını gerektirir; ancak, eşit olmayan nesnelerin farklı karma kodlara sahip olmasını gerektirmez (ancak bu başka nedenlerle istenebilir) [1].
Pastebin.com/f20af40b9 örneği (Oscar'ın en az iki kez ifade ettiği) aşağıdaki gibidir, ancak baskı satırları yerine JUnit iddialarını kullanmak için biraz değiştirilmiştir. Bu örnek, aynı karma kodların çakışmalara neden olduğu ve sınıflar aynı olduğunda yalnızca bir giriş oluşturulduğu önerisini desteklemek için kullanılır (örneğin, bu özel durumda yalnızca bir String):
@Test
public void shouldOverwriteWhenEqualAndHashcodeSame() {
String s = new String("ese");
String ese = new String("ese");
// same hash right?
assertEquals(s.hashCode(), ese.hashCode());
// same class
assertEquals(s.getClass(), ese.getClass());
// AND equal
assertTrue(s.equals(ese));
Map map = new HashMap();
map.put(s, 1);
map.put(ese, 2);
SomeClass some = new SomeClass();
// still same hash right?
assertEquals(s.hashCode(), ese.hashCode());
assertEquals(s.hashCode(), some.hashCode());
map.put(some, 3);
// what would we get?
assertEquals(2, map.size());
assertEquals(2, map.get("ese"));
assertEquals(3, map.get(some));
assertTrue(s.equals(ese) && s.equals("ese"));
}
class SomeClass {
public int hashCode() {
return 100727;
}
}
Ancak, hashcode hikayenin tamamı değildir. Ne pastebin örneği ihmaller de o gerçektir s
ve ese
onlar dize hem "ese" şunlardır: eşittir. Bu nedenle, haritanın içeriğini anahtar olarak s
veya ese
veya kullanarak eklemek veya almak "ese"
eşdeğerdir çünkü s.equals(ese) && s.equals("ese")
.
> Değeri - İkinci test anahtarı nedenidir aynı sınıfta o özdeş hashcodes sonuçlandırmak hatalı olduğunu gösteriyor s -> 1
tarafından üzerine yazılır ese -> 2
zaman map.put(ese, 2)
deney birinde denir. İkinci testte s
ve ese
hala aynı hashcode'a sahip (tarafından doğrulandığı gibi assertEquals(s.hashCode(), ese.hashCode());
) VE bunlar aynı sınıf. Ancak, s
ve ese
olan MyString
örnekler değil, Java, bu testte String
örnekleri - tek farkla eşittir olmak bu test için ilgili: String s equals String ese
yukarıdaki test birinde, oysa MyStrings s does not equal MyString ese
testinde iki:
@Test
public void shouldInsertWhenNotEqualAndHashcodeSame() {
MyString s = new MyString("ese");
MyString ese = new MyString("ese");
// same hash right?
assertEquals(s.hashCode(), ese.hashCode());
// same class
assertEquals(s.getClass(), ese.getClass());
// BUT not equal
assertFalse(s.equals(ese));
Map map = new HashMap();
map.put(s, 1);
map.put(ese, 2);
SomeClass some = new SomeClass();
// still same hash right?
assertEquals(s.hashCode(), ese.hashCode());
assertEquals(s.hashCode(), some.hashCode());
map.put(some, 3);
// what would we get?
assertEquals(3, map.size());
assertEquals(1, map.get(s));
assertEquals(2, map.get(ese));
assertEquals(3, map.get(some));
}
/**
* NOTE: equals is not overridden so the default implementation is used
* which means objects are only equal if they're the same instance, whereas
* the actual Java String class compares the value of its contents.
*/
class MyString {
String i;
MyString(String i) {
this.i = i;
}
@Override
public int hashCode() {
return 100727;
}
}
Daha sonraki bir yoruma dayanarak, Oscar daha önce söylediklerini tersine çeviriyor ve eşitlerin önemini kabul ediyor. Ancak yine de önemli olan "aynı sınıf" değil, eşittir kavramı belirsiz görünüyor (vurgu benim):
"Gerçekte değil. Liste yalnızca hash aynıysa, ancak anahtar farklıysa oluşturulur. Örneğin, bir Dize 2345 karma kodunu verirse ve Tamsayı aynı karma kodu 2345 verirse, tamsayı listeye eklenir çünkü String. eşittir (Tamsayı) yanlıştır. Ancak aynı sınıfa sahipseniz (veya en azından .equals, doğru döndürürse) , aynı giriş kullanılır. Örneğin, yeni Dize ("bir") ve "yeni Dize (" bir ") olarak kullanılır tuşları, aynı girişi kullanacaktır. Aslında bu, HashMap'in BÜTÜN noktasıdır! Kendiniz görün: pastebin.com/f20af40b9 - Oscar Reyes "
eşit sınıfın ve aynı karma kodun önemine açıkça değinen önceki yorumlara kıyasla, eşitlerden söz edilmeden:
"@delfuego: Kendiniz görün: pastebin.com/f20af40b9 Yani, bu soruda aynı sınıf kullanılıyor (bir dakika bekleyin, aynı sınıf doğru kullanılıyor mu?) Bu, aynı hash kullanıldığında aynı girişin kullanıldığı anlamına gelir kullanılmış ve girişlerin "listesi" yok. - Oscar Reyes "
veya
"Aslında bu, performansı artıracaktır. Çarpışmalar ne kadar fazlaysa, hashtable denkleminde daha az giriş yapılması gereken daha az iş var. Hash (iyi görünen) ya da hashtable (harika çalışıyor) değil, bahse girerim nesnenin üzerindedir performansın aşağılayıcı olduğu tasarım. - Oscar Reyes "
veya
"@kdgregory: Evet, ancak yalnızca çarpışma farklı sınıflarda meydana gelirse, aynı sınıf için (durum budur) aynı giriş kullanılır. - Oscar Reyes"
Yine, Oscar'ın gerçekte ne söylemeye çalıştığını yanlış anlayabilirim. Bununla birlikte, orijinal yorumları yeterince kafa karışıklığına neden oldu ve her şeyi bazı açık testlerle temizlemenin akıllıca göründüğü için hiçbir şüphe kalmadı.
[1] - Effective Java, Second Edition , Joshua Bloch'dan:
Bir uygulamanın yürütülmesi sırasında aynı nesne üzerinde birden çok kez çağrıldığında, nesnede eşit s karşılaştırmalarında kullanılan hiçbir bilgi değiştirilmediği sürece, hashCode yöntemi tutarlı bir şekilde aynı tamsayıyı döndürmelidir. Bu tam sayının, bir uygulamanın bir yürütmesinden aynı uygulamanın başka bir yürütmesine kadar tutarlı kalması gerekmez.
İki nesne eşit s (Nesne) yöntemine göre eşitse, iki nesnenin her birinde hashCode yönteminin çağrılması aynı tam sayı sonucunu vermelidir.
İki nesne eşittir s (Nesne) yöntemine göre eşit değilse, bu durumda iki nesnenin her birinde hashCode yönteminin çağrılmasının farklı tam sayı sonuçları üretmesi gerekli değildir. Bununla birlikte, programcı, eşit olmayan nesneler için farklı tam sayı sonuçları üretmenin, karma tabloların performansını artırabileceğinin farkında olmalıdır.