黑马程序员技术交流社区
标题: 关于HashSet中hashcod()和equals()的疑问 [打印本页]
作者: 张振纲 时间: 2012-8-7 16:55
标题: 关于HashSet中hashcod()和equals()的疑问
在HashSet中
主要通过
hashcod()和equals()这两个方法来判断存入的元素是否相同
首先通过哈希值比较
然后再用equals()
我想问的是,我们在设计程序的时候就已经尽可能使每个对象的哈希值不同
那么会不会调用equals方法
如果不调用的话那复写equals方法又有什么其他用处?
作者: 余明辉 时间: 2012-8-7 16:58
据说java在HashCode算法方面,有很大几率出现相同的情况
作者: 马州州 时间: 2012-8-7 17:01
程序是我们写的没错
我想问的是,我们在设计程序的时候就已经尽可能使每个对象的哈希值不同
这句话有问题,我们写程序其实就是写方法,用户通过简单的操作来实现
如果对象是由用户添加的,那么这些对象的哈希值,我们怎么能确定不同?
他们要是传入相同的对象呢?
传入对象不一定是我们传入的了,是由用户添加的对象,那么他们就有可能添加了重复的对象
如果没有这个判断的话,就会出现重复
那么我们所写的软件安全性也不高
所以equals是必须得有的
作者: 杜鹏云 时间: 2012-8-7 17:24
马州州 发表于 2012-8-7 17:01 
程序是我们写的没错
我想问的是,我们在设计程序的时候就已经尽可能使每个对象的哈希值不同
这句话有问题, ...
HashSet的实现是通过HashMap的KeySet做为存储结构的,大家都知道哈希算法为了避免键值冲突,一般有两个方法:二次哈希和链地址法。则HashMap就是用的链地址法。
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
看上面代码中下划线的黑体字,就是用hashCode()方法得到键值的桶(桶的概念是一个具有相同哈希值的容器)地址,然后才在一个桶中调用equals方法比较对象是否相等。
其实到这里我们已经知道了hashCode为什么一定要重写了。如果为两个实例即使equals方法成立,可是如果不在一个桶中,则都本不会调用equals方法比较了。
-
2011082413523665.png
(501.8 KB, 下载次数: 43)
作者: 牛杨 时间: 2012-8-7 17:30
马州州 发表于 2012-8-7 17:01 
程序是我们写的没错
我想问的是,我们在设计程序的时候就已经尽可能使每个对象的哈希值不同
这句话有问题, ...
我想楼主是不太清楚为什么我们定义一个类时要重写hashCode()方法和equals()方法。
首先在Object类里面有hashCode()和 equals()方法。
但是Object类里面的hashCode()是通过对象实例的来确定出这个对象实例的哈希码值的。同样Object类里面的equals()方法也是通过比较两个对象实例的地址值来确定对象是否相等的。所以默认情况下两个对象是通过比较引用值(也即地址值)是否相等来确定两个对象是否相等。
但是如果我们自定义一个类,而又想根据对象里面的属性字段(成员属性)来比较两个对象是否相等的话,那么就需要在自定义的类中重写这两个方法了。
比如我们定义一个person类,如果两个person对象的姓名和年龄相等 这两个对象就是相等的话 应该这样定义:
class Person
{
private String name;
private int age;
public Person(String name , int age)
{
this.name=name;
this.age=age;
}
public boolean equals(Object obj) //重写Object类里面的equals方法
{
if( !(obj instanceof Person) )
return false;
Person p=(Person)obj;
return this.name.equals(p.name)&&this.age==p.age;
}
public int hashCode() //重写Object类里面的hashCode方法
{
return name.hashCode()+age*37;
}
}
作者: 马州州 时间: 2012-8-7 18:23
牛杨 发表于 2012-8-7 17:30 
我想楼主是不太清楚为什么我们定义一个类时要重写hashCode()方法和equals()方法。
首先在Object类里 ...
你说的这个我也知道啊,楼主问的是再确定hash值不同的情况下,可不可以不做equals比较
而不是问怎么比较的
作者: 马州州 时间: 2012-8-7 18:30
我想说的是,希望大家在回答问题的时候看一下楼主的需求,前面两位同学回答的很到位,但是我想说的是,真的不写equals程序也没有错,只是比较的时候会出问题,会出现重复,而不是程序不能运行
equals比较是为了加强程序的严谨性,而不是必须得覆盖,如果一个需求,允许出现重复元素,那么你还要复写equals么?
作者: 官文昌 时间: 2012-8-7 18:48
无语,程序是你写的,你写程序干嘛?写出来不就是给别人用吗。别人在用你写的程序时,请问他知道吗????
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |