hashCode为什么这么写?
--------------------编程问答--------------------
public class CatHash {
private String name;
private Date birthday;
public CatHash() {
}
public CatHash(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getBirthday() {
return birthday;
}
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof CatHash))
return false;
final CatHash cat = (CatHash) other;
if (!getName().equals(cat.getName()))
return false;
if (!getBirthday().equals(cat.getBirthday()))
return false;
return true;
}
public int hashCode() {
int result = getName().hashCode();
result = 25 * result + getBirthday().hashCode();
return result;
}
}
--------------------编程问答-------------------- 保证这个对象的唯一性。。 --------------------编程问答-------------------- 那个25应该换成一个质数,如37之类。 --------------------编程问答-------------------- 遗憾哪,两位大神的话我都没懂 --------------------编程问答--------------------
public class CatManager {
public static void main(String[] args) {
Date d = new Date();
CatHash bigC = new CatHash("BigCat", d);
CatHash smallC = new CatHash("BigCat", d);
System.out.println(bigC == smallC); // 1
System.out.println(bigC.equals(smallC)); // 2
Set<CatHash> set = new HashSet<CatHash>(); // 3
set.add(bigC);
set.add(smallC);
Iterator iter = set.iterator();
while (iter.hasNext()) {
System.out.println(iter.next().hashCode());
}
for (CatHash cat : set){
System.out.println(cat.getName());
System.out.println(cat.getBirthday());
}
System.out.println(set.size());
}
}
Change to:
--------------------编程问答--------------------
while (iter.hasNext()) {
CatHash cat = (CatHash)iter.next();
System.out.println(cat.getName());
System.out.println(cat.getBirthday());
System.out.println(cat.hashCode());
}
import java.util.Date;
import java.util.HashMap;
public class CatHash {
private String name;
private Date birthday;
public CatHash() {
}
public CatHash(String name, Date birthday) {
this.name = name;
this.birthday = birthday;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public Date getBirthday() {
return birthday;
}
public boolean equals(Object other) {
if (this == other)
return true;
if (!(other instanceof CatHash))
return false;
final CatHash cat = (CatHash) other;
if (!getName().equals(cat.getName()))
return false;
if (!getBirthday().equals(cat.getBirthday()))
return false;
return true;
}
public int hashCode() {
int result = getName().hashCode();
result = 25 * result + getBirthday().hashCode();
return result;
}
public static void main(String[] args) {
HashMap hashMap = new HashMap();
CatHash catHash = new CatHash("",new Date());
hashMap.put(catHash, 1);
System.out.println(hashMap.get(catHash));
catHash.setName("sssssss");
System.out.println(hashMap.get(catHash));
}
}
结果如下:
1
null
很难说这种写法是正确地,作为一个键它的hashCode应该是固定不变 --------------------编程问答-------------------- 好的hashCode()
因此,要想使hashCode()实用,它必须速度快并且必须有意义。也就是说,它必须基于对象的内容生成散列码。散列码不必是独一无二的(应该更关注生成速度,而不是唯一性),但是通过hashCode()和equals(),必须能够完全确定对象的身份。
因为在生成桶的下标前,hashCode()还需要做进一步的处理,所以散列码的生成范围并不重要,只要是int即可。
还有另外一个影响因素:好的hashCode()应该能够产生分布均匀的散列码。如果散列码都集中在一块,那么HashMap或者HashSet在某些区域的负载会很重,这样就不如分布均匀的散列函数快。
1.给int变量result赋予某个非零常量
2.为对象内每个有意义的域f(即每个可以做equals()操作的域)计算出一个int散列码e:
域类型 计算
boolean c=(f?0:1)
byte、char、short或int c=(int)f
long c=(int)(f^(f>>>32))
float c=Float.floatToIntBits(f);
double long l = Double.doubleToLongBits(f);
c=(int)(l ^ (l>>>32))
Object,其equals()调用这个域的equals() c=f.hashCode()
数组 对每个元素应用上述规则
3.合并计算得到的散列码:
result = 37*resutl + c;
4.返回result。
5.检查hashCode()最后生成的结果,确保相同的对象有相同的散列码。
--------------------编程问答-------------------- thinking in java中的说法,也就是为什么是37的原因 --------------------编程问答--------------------
作为一个键,应该是一个不能被修改的类,像String和Integer这样的包装类。 --------------------编程问答--------------------
// Creating a good hashCode().
package containers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CountedString {
private static List<String> created = new ArrayList<String>();
private String s;
private int id = 0;
public CountedString(String str) {
s = str;
created.add(s);
// id is the total number of instances
// of this string in use by CountedString:
for (String s2 : created) {
if (s2.equals(s)) {
id++;
}
}
}
@Override
public String toString() {
return "String: " + s + " id: " + id + " hashCode(): " + hashCode();
}
@Override
public int hashCode() {
// The very 易做图 approach:
// return s.hashCode() * id:
// Using Joshua Bloch's recipe:
int result = 17;
result = 37 * result + s.hashCode();
result = 37 * result + id;
return result;
}
@Override
public boolean equals(Object o) {
return o instanceof CountedString && s.equals(((CountedString) o).s)
&& id == ((CountedString) o).id;
}
public static void main(String[] args) {
Map<CountedString, Integer> map = new HashMap<CountedString, Integer>();
CountedString[] cs = new CountedString[5];
for(int i = 0; i < cs.length; i++){
cs[i] = new CountedString("hi");
map.put(cs[i], i);//Autobox int ->Integer
}
System.out.println(map);
for(CountedString cstring : cs){
System.out.println("Looking up " + cstring);
System.out.println(map.get(cstring));
}
}
}
这是thinking in java中的代码,我想这样的类才能作为map的key --------------------编程问答--------------------
作为一个键,应该是一个不能被修改的类,像String和Integer这样的包装类。
结果如下:
1
null
why??????? --------------------编程问答--------------------
这样的类有什么特征?
这个问题还挺复杂,我得好好消化一下。大神,如果只推荐一本书的话,看哪本比较好? --------------------编程问答-------------------- 这么写不够好 25应该换成31 或者其他质数 jvm有一项优化可以 31*i=i<<<5-i --------------------编程问答--------------------
结果如下:
1
null
why???????
catHash.setName("sssssss");
之后,和原来put时的不相等了, --------------------编程问答-------------------- 机器产生hashcode并不能保证两个对象的hashcode不同,而且java验证是否为同个对象不仅仅是hashcode相等,hashcode相等时两对像相等的必要条件,还有其他的比较的东西。
而我们要实现验证两对象是否是同一个的话就必须要重写equals方法,为对象产生出一个比较独特的hashcode,基本保证无法产生相同hashcode。
补充:Java , Java SE