您的位置:首页 > 其它

深入详解SetHash的元素为什么要重写hashCode和equals方法

2017-06-15 17:26 627 查看
在Object这个类中hashCode是本地方法,它的值与对象在内存中的地址有关,所以不会存在两个hashCode返回值相同的对象,equals是比较对象的引用是否相等

hashCode方法的目的是什么呢?

—它是为hash table中插入为提供hash数值

SetHash:一个是无序不重复的集合,你知道为什么吗?

因为SetHash根据hashCode返回值和equals来判断两个对象是否相同(不止地址还指内容)

在HashCode的返回值判断插入位置,equals判断该位置上是否有和要插入的元素相同的

所以要保证SetHash插入的元素不重复,那就要重写hashCode和equals

我们先举一个没有重写hashCode和equals的例子吧

先定义一个元素类Point

class Point{
private int a;
private int b;
public Point(int a,int b){
this.a = a;
this.b = b;
}
@Override
public String toString(){
return "("+a+","+b+")";
}


再定一个Test类

public class TestHashSet {

public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet<Point> hash = new HashSet<Point>();
hash.add(new Point(4,5));
hash.add(new Point(4,5));
hash.add(new Point(1,5));
for(Point p:hash){
System.out.println(p);
}
}

}


按理论上讲应该输出:

(4,5),(1,5)这两个值,因为有重复的(4,5)

但是实际输出却是这样



为什么呢?因为没有重写hashCode导致两个(4,5)的插入位置不一样或者插入一样但是,两个对象的引用地址不一样

重写equals的目的是:让两个(4,5)引用地址不一样,但内容一样的对象是相等的

重写hashCode的目的:让A.equals(B)为true的两个对象的hashCode返回值一样

在这里有可能有小伙伴有疑问?问可不可以不重写hashCode呢?

答案是不可以,为什么?让我们有例子来解答疑惑

还是刚才个例子,我们重写了equals方法

class Point{
private int a;
private int b;
public Point(int a,int b){
this.a = a;
this.b = b;
}
@Override
public String toString(){
return "("+a+","+b+")";
}

***@Override
public boolean equals(Object obj){

if(this==obj)
return true;
if(!(obj instanceof Point))
return false;
Point p = (Point)obj;

return this.a == p.a && this.b == p.b;

}***
}


测试类

import java.util.HashSet;

public class TestSet {

public static void main(String[] args) {
// TODO Auto-generated method stub
HashSet<Point> hash = new HashSet<Point>();
Point p = new Point(4,5);
Point p1 = new Point(4,5);
hash.add(p);
System.out.println(hash.contains(p1));
}

}


你们猜结果为什么?应该是true吧

但是输出却为false,为什么呢?

因为p和p1的hashCode不一样就用可能不会插入到同一个位置,所以会返回false

因此使用HashSet 的add()方法插入元素的时候:

|- HashSet会自动调用元素的hashCode()方法。

|- 然后根据hashCode()方法的返回值 来决定元素要插入的位置。

|- 如果该位置上已经存在元素了 则会调用该元素equals()方法进行比较。

|- 如果两个元素相等 则丢掉欲插入的元素。

|- 如果两个元素不相等 则新元素会被加入到另一个位置(通过冲突检测来决定哪一个位置),这样就消除了重复。

|- 范例1中使用的是Point类 其并没有重写这2个方法。因此无法消除重复。

|- 范例2中使用的是String类,在String类已经重写完了Object类的equals()和hashCode()方法,所以可以消除重复。

说白了:

|- 如果想完整的使用HashSet类 那么最少要重写equals()和hashCode()方法。

|- 重写hashCode() 用于获得元素的存储位置。

|- 重写equals() 用于在两个元素的位置相同的时候 比较两个元素是否相等。

总结一下:

Set接口有两个子类:HashSet和TreeSet 。

|- HashSet

|- 特点:在不存在重复元素的基础上,还可以进行高速的存取元素。

|- 要求:需要为您的类重写hashCode()和equals()方法。

|- TreeSet

|- 特点:在不存在重复元素的基础上,还可以将元素自动排序。

|- 要求:需要为您的类实现Comparable接口,并重写compareTo方法。

|- 重写compareTo() 可以同时完成两份工作  排序和消除重复。

能帮到你们,我十分荣幸
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  equals hashcode
相关文章推荐