这几天一直在纠结一个问题,毕老师在视频中讲到,Set集合的特点是可以保证元素的唯一性(即保证元素的不重复),我觉得这个说法不大准确,为什么呢,其实是有办法让它出现“重复”的元素,为什么打引号?因为这涉及到你怎么理解的问题,请看下面的例子:
import java.util.*;
class A
{
private int a;
A(int a){this.a=a;}
public int hashCode() //重写Object的hashCode方法
{
return this.a;
}
public boolean equals(Object obj)//重写Object的equals方法
{
A r=(A)obj;
if (r.a==this.a)
{
return true;
}
return false;
}
public void Get(){System.out.println(this.a);}
public void Set(int a){this.a=a;}
}
class Blog
{
public static void main(String[] args)
{
HashSet hs=new HashSet(); //没有使用泛型,其实不大严格
hs.add(new A(9));
hs.add(new A(8));
hs.add(new A(-6));
hs.add(new A(3));
hs.add(new A(5));
hs.add(new A(8)); //这个必然添加不进去,因为根据规则首先比较的是A对象的hashCode方法,而此处被改写为返回类A的对象中的a值
/* HashSet s=new HashSet();
s.add(new Integer(1));
s.add(new Integer(2));
s.add(new Integer(3));
s.add(new Integer(1));
*/
Show(hs);
Iterator it=hs.iterator();
A first=(A)it.next();
first.Set(8); //修改第一个元素的值
System.out.println("这是修改之后的值");
Show(hs);
}
static void Show(HashSet hs)
{
Iterator it=hs.iterator();
while (it.hasNext())
{
A aa=(A)it.next();
aa.Get();
}
}
}
上面的结果说明什么?为什么我刚刚说那个"重复"全看个人怎么理解?
我个人认为当集合的元素是引用型时,若我们不去重写hashCode方法和equals方法时,new出来的两个对象的hashcode极有可能不同(为什么不是一定?因为群友说还是有可能相同,具体原因我也不是很清楚,不了解这个算法,希望大虾指导),如果不同,系统会认为两个是不同的对象直接存进集合,若是相同那么在比较equals方法的时候会比较两个引用型数据的地址,下面的Object源码可以证明:
public boolean equals(Object obj) {
return (this == obj);
综合起来可以这样说,当集合的元素是引用类型时,若我们没有重写hashCode方法和equals方法,元素必定不相同,但是当我们重写了这两个方法之后,这个"相同"就具有另外的含义了,这个含义是我们定义的,在上面的程序中,这个"相同"的含义是,只要两个元素的a值是一样的话,我们就认为相同,程序中重新改写了第一个元素的a属性,这样就这个定义的话,我们就实现了元素的相同。
另外还有一个重要的问题要解决,依照上面对引用类型相同的定义,new 产生的两个引用型数据在不改写hashCode方法和equals方法时,两元素必然不同,那么这样的话,
HashSet s=new HashSet();
s.add(new Integer(1));
s.add(new Integer(2));
s.add(new Integer(3));
s.add(new Integer(1));
这种做法最后的结果是不是应该有两个1呢??当然,如果我们没改写的话,当然应该是两个呢,但事实上Integer类确实改写了,下面的源码可以证明这点:
public int hashCode() {
return value;
}
public Integer(int value) {
this.value = value;
}
hashcode比较的就是他的属性而不是经计算得到的hashcode值