包含HashMap和哈希碼質疑哈希映射和哈希碼的變化,如何判斷對象已經改變?
有一個POJO,過書面哈希碼,等於幫助一個partcular比較(這裏沒有顯示)
package coll.hset;
public class Dat {
private String name;
private String dat;
private int aa;//some business reason not used in hashcode and equals
public int hashCode(){
int h = 0 ;
if(name != null){
h += name.hashCode();
}
if(dat != null){
h += dat.hashCode();
}
return h;
}
public boolean equals(Object o){
if(o instanceof Dat){
Dat oo = (Dat)o;
if(this.name ==null && oo.name != null){
return false;
}else if(!name.equals(oo.name)){
return false;
}
if(this.dat ==null && oo.dat != null){
return false;
}else if(!dat.equals(oo.dat)){
return false;
}
return true;
}
return false;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDat() {
return dat;
}
public void setDat(String dat) {
this.dat = dat;
}
public int getAa() {
return aa;
}
public void setAa(int aa) {
this.aa = aa;
}
}
的用戶應用程序:
package coll.hset;
import java.util.HashSet;
import java.util.Random;
public class App {
final static int SZ = 2^8;
/**
* @param args
*/
public static void main(String[] args) {
Random rndm = new Random();// to create random data
Dat dd;// reference while filling up set
Dat[] d2 = new Dat[500];// save a few here for later ops
int fills = 0;
HashSet<Dat> dats = new HashSet<Dat>();// set
for (int i = 0; i < 10000; i++) {
dd = new Dat();
dd.setAa(i);
// fill random dat and name.
char v = (char) (65 + rndm.nextInt(26));
dd.setDat("a " + v);
v = (char) (65 + rndm.nextInt(26));
char v1 = (char) (65 + rndm.nextInt(26));
char v2 = (char) (65 + rndm.nextInt(26));
char v3 = (char) (65 + rndm.nextInt(26));
char v4 = (char) (65 + rndm.nextInt(26));
dd.setName(v + " " + v1 + v2 + v3 + v1 + v + v4);
dats.add(dd);
if (i % 60 == 0) {
d2[fills++] = dd;
}
}
Dat ref = d2[0];
int hash = hash(ref.hashCode());
int idx = indexFor(hash, SZ);
boolean has1 = dats.contains(d2[0]);
System.out.println("has d 0 :" + has1 + ", name :" + ref.getName() + ", hash :" + ref.hashCode() + ". hash2 :" + hash + ", idx :" + idx + ", when size of table :" + SZ);
d2[0].setName(ref.getName() + "l");
// d2[0].setName(ref.getName() + "l");
d2[0].setName("Tony G");
// ref.setDat("sd=");
hash = hash(ref.hashCode());
// if you run this many times will see that for some cases the table is the same, so a quicker rehash, instead of remove and add back after change is what I'm after
idx = indexFor(hash, SZ);
has1 = dats.contains(d2[0]);
System.out.println("has d 0 after name change :" + has1 + ", name :" + ref.getName() + ".");
System.out.println("has d 0 :" + has1 + ", name :" + ref.getName() + ", hash :" + ref.hashCode() + ". hash2 :" + hash + ", idx :" + idx + ", when size of table :" + SZ);
System.out.println(" at : " + new java.util.Date());
}
static int hash(int h) {
// From Sun Java impl
/*
*/This function ensures that hashCodes that differ only by // constant multiples at each bit position have a bounded // number of collisions (approximately 8 at default load factor).
*/
h ^= (h >>> 20)^(h >>> 12);
return h^(h >>> 7)^(h >>> 4);
}
static int indexFor(int h, int length) {
return h & (length - 1);
}
}
由於預期第二次搜索說出來Dat對象d2 [0]即使認爲它不在集合中。 我知道如何解決它 - 一種方法 - 刪除它,改變它然後再添加它。有沒有其他辦法可以告訴我們我們正在改變一個特定的對象?
能看到甲骨文/ Sun的Java HashMap中怎麼老調重彈它的自我。問題是 - 我們可以添加一個告訴集合的新方法 - 請重新哈希這個對象,而不是刪除和添加它,所以它更有效。
如果你運行上面的代碼很多次會看到,某些情況下,表是相同的(在之前和之後突變對象的散列碼),所以更快的翻版,而不是刪除和添加回來後的變化是什麼我之後,利用了這個事實,只有在換桶的時候纔會反覆。
由於您的非說話變量,代碼非常難以閱讀。例如。如果'rr'的名字是'random',那會更好。 –
簡單:_Don't改變它!_ – Seelenvirtuose
所以告訴我們的商業用戶 - 嘿,請不要改變你的名字或目前的地址?我認爲不是 – tgkprog