Java的HashSet类

如果要查找一个集合中是否包含了某个对象,那么就需要把这个对象和这个集合中的每个对象依次进行比较和判断,直到找到这个对象为止,或者把所有对象都比较一次为止(如果最后一个对象才是要查找的对象,或者集合中没有包含要查找的对象)。当集合中的对象数量较多时,效率就很低。为了提高效率,提出了Hash算法。Hash算法对每一个对象都计算出一个Hash码,根据Hash码把对象分配到某个存储区域中,比如一个集合包含了很多人,根据国籍,中国人是一个存储区域,美国人是一个存储区域,英国人是一个存储区域,......。这样如果要查找该集合是否包含了某个中国人,就到中国人的存储区域去比较就行了,这样大大提高了效率。

Java中实现了Hash的集合是HashSet。HashSet查找某个对象时,首先用hashCode()方法计算出这个对象的Hash码,然后再根据Hash码到相应的存储区域用equals()方法查找,从而提高了效率。由于是集合,所以同一个对象只能有一个。

hashSet的例子如下所示:

package my;

import java.util.HashSet;
import java.util.Set;

class Person{

    // 性别
    String sex;
    // 姓名
    String name;
    // 身高
    Double hei;
    // 体重
    Double wei;

    public Person(String n, String s, Double h, Double w){
        this.name=n;
        this.sex=s;
        this.hei=h;
        this.wei=w;
    }

    public String toString(){
        return "\n姓名:"+this.name+"  性别:"+this.sex+"  身高:"+this.hei+"  体重:"+this.wei;
    }

}

public class myHS {

    private static Set<Person> mySet = new HashSet<Person>();
    public static void main(String[] args) {
        mySet.add(new Person("Tom","Male",170.0,70.0));
        mySet.add(new Person("Peter","Male",175.0,70.0));
        mySet.add(new Person("Kate","Female",168.0,60.0));
        mySet.add(new Person("Alice","Female",161.0,55.0));
        mySet.add(new Person("Jack","Male",190.0,95.0));
        mySet.add(new Person("Jack","Male",190.0,95.0));
        System.out.println(mySet);
    }

}

以上例子先定义了Person类,然后定义了一个HashSet,并加入了5个Person到该集合,其中1个人加入了两次,运行结果如下:

可见Jack是同一个人,却在集合中出现了两次,这是什么原因呢?这是因为,Person是Object的子类,而Object类的equals()方法是根据对象的内存地址来判断两个对象是否相等的,由于两次插入的Jack的内存地址肯定不相同,所以判断的结果是不相等,所以两次都插入了。于是,我们需要覆写equals()方法来判断两个对象是否是同一个对象。

    // 覆写equals方法
    public boolean equals (Object obj){
        // 地址相等,则肯定是同一个对象
        if(this==obj){
            return true;
        }
        // 类型不同,则肯定不是同一类对象
        if(!(obj instanceof Person)){
            return false;
        }
        // 类型相同,向下转型
        Person per=(Person) obj;
        // 如果两个对象的姓名和性别相同,则是同一个人
        if(this.name.equals(per.name)&&this.sex.equals(per.sex))
            return true;
        return false;
    }

覆写equals()方法以后,运行结果如下:

可见Jack仍然被插入了两次,这是什么原因呢?这是因为Object的Hash码返回的是对象的Hash地址,而两个对象的Hash地址肯定是不相等的,所以6次插入的对象被存储在6个存储区域,equals()方法根本没有运行。于是,还需要覆写hashCode()方法,根据姓名来计算对象的Hash码。

    // 覆写hashCode方法
    public int hashCode(){
        return this.name.hashCode();
    }

运行结果如下:

可见,Jack只插入了一次,终于正确了。如果根据性别来计算对象的Hash码,结果也是正确的,Jack也只会被插入1次。但是,如果两个对象的性别不同,如下所示:

        mySet.add(new Person("Jack","Male",190.0,95.0));
        mySet.add(new Person("Jack","Female",190.0,95.0));

则两个对象都会被插入:

这是因为虽然两个对象的Hash码相同(不论是按照姓名,还是按照性别来计算,Hash码都是相同的),但是equals()方法判断这两个对象不相等,于是都插入了。

时间: 2024-10-24 01:02:35

Java的HashSet类的相关文章

JDK1.8源码(八)——java.util.HashSet 类

在上一篇博客,我们介绍了 Map 集合的一种典型实现 HashMap ,在 JDK1.8 中,HashMap 是由 数组+链表+红黑树构成,相对于早期版本的 JDK HashMap 实现,新增了红黑树作为底层数据结构,在数据量较大且哈希碰撞较多时,能够极大的增加检索的效率.了解 HashMap 的具体实现后,我们再来介绍由 HashMap 作为底层数据结构实现的一种数据结构——HashSet.(如果不了解 HashMap 的实现原理,建议先看看 HashMap,不然直接看 HashSet 是很难

Java API —— Set接口 &amp; HashSet类 &amp; LinkedHashSet类

1.Set接口 1)Set接口概述 一个不包含重复元素的 collection,无序(存储顺序和取出顺序不一致),唯一.  (List有序,即存储顺序和取出顺序一致,可重复) 2)Set案例 存储字符串并遍历 存储自定义对象并遍历 2.HashSet 1)HashSet类概述 不保证 set 的迭代顺序:特别是它不保证该顺序恒久不变. 2)HashSet如何保证元素唯一性 底层数据结构是哈希表(元素是链表的数组) 哈希表依赖于哈希值存储 添加功能底层依赖两个方法: · int hashCode(

Java——(三)Collection之Set集合、HashSet类

------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- 一.Set集合 Set集合不允许包含相同的元素,如果试图把两个相同的元素加入同一个Set集合中,则添加 操作失败,add方法返回false,而新元素不会被加入. Set判断两对象相同不是使用==运算符,而是根据equals方法.也就是说,只要两个对象用 equals方法比较返回true,Ser就不会接受这两个对象:反之,只要两个对象用equals方法比较 返回false,SEt就会接受这两个对

Java HashSet类

HashSet扩展AbstractSet和实现Set接口.它创建一个使用一个哈希表进行存储的集合. 哈希表通过使用一种称为哈希机制存储信息.在散列法中,键的信息内容是用来确定一个唯一的值,称为它的散列码. 散列码,用作在其中与该键相关联的数据被存储在索引中.键转化为它的哈希码是自动进行的. HashSet类支持四个构造函数.第一种形式构造一个默认的哈希集合: HashSet( ) 下面的构造形式初始化哈希使用c的元素集. HashSet(Collection c) 下面的构造形式初始化哈希设置为

数据结构-List接口-LinkedList类-Set接口-HashSet类-Collection总结

一.数据结构:4种--<需补充> 1.堆栈结构:     特点:LIFO(后进先出);栈的入口/出口都在顶端位置;压栈就是存元素/弹栈就是取元素;     代表类:Stack;     其它:main方法最后一个出去; 2.数组结构:     特点:一片连续的空间;有索引,查找快;增删慢;     代表类:ArrayList;     应用场景:用于查询多的场景,如天气预报; 3.队列结构:     特点:FIFO(先进先出);入口/出口在两侧;     代表:Queue接口     应用场景

Java API —— TreeSet类

1.TreeSet类  1)TreeSet类概述 使用元素的自然顺序对元素进行排序 或者根据创建 set 时提供的 Comparator 进行排序 具体取决于使用的构造方法.   2)TreeSet是如何保证元素的排序和唯一性的 底层数据结构是红黑树(红黑树是一种自平衡的二叉树) 例子1: package treesetdemos; import java.util.TreeSet; /** * Created by gao on 15-12-17. */ /* * TreeSet:能够对元素按

Java集合-HashSet

HashSet类,是存在于java.util包中的类 .同时也被称为集合,该容器中只能存储不重复的对象.底层是由HashMap来存储的,因为HashSet不能重复,你知道HashMap的键不能重复就明白了这一个原理了,所以对于HashMap很熟悉的话对于HashSet就能够很快的知道底层实现.HashMap传送门(HashMap源码分析). HashSet概述 此类实现了Set接口,由哈希表(实际上是HashMap实例)支持. 对集合的迭代次序不作任何保证; 特别是不会保证这种顺序会持久不变(不

day07(Set接口,HashSet类,hashcoad(),Collections工具类,Map集合)

Set接口 set接口的实现类特点 1.无序(取出来的顺序和存进去的数据的顺序不一致) 2.唯一(数据不能存相同的) 底层是用Map集合写的 HashSet类  实现了  set接口       唯一性  public class HashSetTest { public static void main(String[] args) { HashSet<String> hs=new HashSet<String>(); hs.add("hello"); hs.

Java 最常用类(前100名)来自一万个开源项目

大部分的 Java 软件开发都会使用到各种不同的库.近日我们从一万个开源的 Java 项目中进行分析,从中提取出最常用的 Java 类,这些类有来自于 Java 的标准库,也有第三方库.每个类在同一个项目中只计数一次,下面的列表中显示前 100 名的类. 以下列表中按使用最多的类进行排序,第三个数值表示 10000 个项目里使用到该类的项目数,而完整的列表请看 here. java.util.ArrayList(6958) java.io.IOException(6866) java.util.