hashset中equals和hashcode方法重写问题

Collection接口有两个子接口:List接口和Set接口。
List本身就是一个变长的数组,当数组中的空间用完后,就自动开辟一个更大的数据,然后将原来的数据复制到新数组中,以此来扩展数据的长度。ArrayList就是如此。List接口中的元素可以重复。
而Set接口是不允许存在重复元素的。
先看一个例子,现在写一个Point类:[code=java]package org.cxy.collection;

public class Point {
        private int x;
        private int y;
        public Point(int x,int y){
                this.x = x;
                this.y = y;
        }
        public String toString(){
                return "坐标(x="+this.x+",y="+this.y+")"        ;
        }
}[/code]然后写一个测试类:[code=java]package org.cxy.collection;

import java.util.*;

public class HashSetDemo {
        public static void main(String[] args){
                HashSet< oint> hash = new HashSet< oint>();
                hash.add(new Point(5,4));
                hash.add(new Point(5,4));
                hash.add(new Point(1,2));
                for(Point p:hash){
                    System.out.println(p);
                }
        }
}[/code]执行结果:[code=java]坐标(x=5,y=4)
坐标(x=5,y=4)
坐标(x=1,y=2)[/code]刚才说了,Set接口是可以消除重复元素的,但是程序的执行结果,却存在了相同的元素。这是为什么?

换成String类呢?[code=java]package org.cxy.collection;

import java.util.*;

public class HashSetDemo {
        public static void main(String[] args){
                HashSet hash = new HashSet();
                hash.add("1");
                hash.add("1");
                hash.add("2");
                for(String str:hash){
                        System.out.println(str);
                }
        }
}[/code]程序执行的结果:[code=java]2
1[/code]结果居然没有重复元素,这又是为什么?还有,为什么先加入的是“1”,而先输出的元素确实“2”?
咱们一个个的来解决。

    如果您学习过《数据结构》这门课程,对Hash应该有点印象,对,hash表。他的特点就是高速存取,而且它是所有数据结构中存取元素速度最快的一种。而HashSet接口就是基于哈希表来设计的。
    为什么Hash表最快?数据的存储首先就是需要查找出数据将要存取的位置,顺序、折半、索引表、二叉查找树的查找效率都与查找表(待查找元素组成的集合)的长度紧密相关。都需要使用关键字不断的和查找表中的元素进行匹配。而查找的终极、必杀的做法是不去或很少进行元素的匹配。散列查找就是通过散列函数来计算元素的位置,从而尽可能的减少匹配次数,以此来提高存取速度。
    存取元素的位置,通过计算来得到。在Java中,这个计算的过程就由hashCode方法来完成。
    当将元素A、B依次插入到HashSet中,输出数据的时候,A并不一定排在B的前面,因为元素存储位置是由元素的hash码来确定的。因此咱们也说,HashSet是无序存放元素的。
    但是,凡是都有万一,万一插入数据的时候,计算出来的位置上,已经存在了元素,那又该怎么办?在《数据结构》中,存在了“冲突检测机制”,这个东西的目的,就是当目标位置存在元素的时候,就给待插入元素新找一个位置。
    而在Java中,虽然Set接口,本身要求其内的元素不能重复,但是谁来保证元素不重复呢? 答案当然就是通过咱们自己重写hashCode()和equals()方法。

因此使用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() 可以同时完成两份工作   排序和消除重复。

你可能感兴趣的:(算法)