在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() 可以同时完成两份工作 排序和消除重复。
能帮到你们,我十分荣幸