首页 > 其他分享 >浅谈集合HashSet

浅谈集合HashSet

时间:2023-03-20 20:14:34浏览次数:40  
标签:浅谈 HashSet Object 哈希 Student 集合 new HashMap

HashSet

简介

HashSet集合继承于Collection集合,Collection集合的常用方法也在HashSet中同样适用。

  • 底层原理:HashSet集合底层采用哈希表存储数据,底层是new 了一个HashMap,add方法是利用map.put()方法。

    public HashSet() {
        map = new HashMap<>();
    }
    

    HashSet是用HashMap来保存数据,而主要使用到的就是HashMap的key。

    // 底层使用HashMap来保存HashSet的元素
    private transient HashMap<E,Object> map;
    // 由于Set只使用到了HashMap的key,所以此处定义一个静态的常量Object类,来充当HashMap的value
    private static final Object PRESENT = new Object();
    

    看到 private static final Object PRESENT = new Object();不知道你有没有一点疑问呢。

    这里使用一个静态的常量Object类来充当HashMap的value,既然这里map的value是没有意义的,为什么不直接使用null值来充当value呢?

    比如写成这样子 private final Object PRESENT = null ;

    我们都知道的是,Java首先将变量PRESENT分配在栈空间,而将new出来的Object分配到堆空间,这里的new Object()是占用堆内存的(一个空的Object对象占用8byte),而null值我们知道,是不会在堆空间分配内存的。

    那么想一想这里为什么不使用null值。想到什么吗,看一个异常类 java.lang.NullPointerException,这绝对是Java程序员的一个噩梦,这是所有Java程序猿都会遇到的一个异常,你看到这个异常你以为很好解决,但是有些时候也不是那么容易解决,Java号称没有指针,但是处处碰到NullPointerException。所以啊,为了从根源上避免NullPointerException的出现,浪费8个byte又怎么样,在下面的代码中我再也不会写这样的代码了if (xxx == null) { … } else {….}。

  • 哈希表是一种对于增删改查数据性能都较好的数据结构

哈希表组成:

  • JDK8之前:数组 + 链表
  • JDK8开始:数组 + 链表 + 红黑树(后面会出一期红黑树的文章)

哈希值:对象的整数表示形式

  • 根据HashCode方法算出来的int类型的整数
  • 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算。
  • 一般情况下,会重写HashCode方法,利用对象内部的属性值计算哈希值。

对象的哈希值特点:

  • 如果没有重写HashCode方法,不同对象计算出来的哈希值是不同的。
  • 如果已经重写hashcode方法,不同的对象只要属性值相同,计算出的哈希值就是一样的
  • 在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)
  • 如果集合存储的是自定义的对象,必须要重写hashCode方法和equals方法
public class A01_HashSetDemo1 {
    public static void main(String[] args) {

        Student s1 = new Student("zhangsan",19);
        Student s2 = new Student("zhangsan",19);

        //没有重写HashCode方法
        System.out.println(s1.hashCode());//哈希值为460141958
        System.out.println(s2.hashCode());//哈希值为1163157884
    }
}

重写HashCode方法:

 @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

得到新的哈希值:

		Student s1 = new Student("zhangsan",19);
        Student s2 = new Student("zhangsan",19);

        System.out.println(s1.hashCode());//-1461067296
        System.out.println(s2.hashCode());//-1461067296

可以发现重写HashCode方法后只要属性值相同,计算出来的哈希值是相同的。

哈希碰撞(小概率事件):

		System.out.println("abc".hashCode());//96354
        System.out.println("acD".hashCode());//96354

HashSet JDK8 以前的底层原理

HashSet<String> hm = new HashSet<>();
  1. 创建一个默认长度16,默认加载因子0.75的数组,数组名为table

    • 当元素 为 16 * 0.75 = 12 时,就会触发扩容机制,扩大为原来数组的两倍。也就是32。
    • 当链表长度大于8而且数组数组长度大于等于64。就会将数组转成红黑树,从而提高查找效率。
  2. 根据元素的哈希值跟数组的长度计算出应存入的位置。

    int index = (数组长度 - 1)& 哈希值 ;

  3. 判断当前位置是否为null,如果是null直接存入。

  4. 如果位置不为null,表示有元素,则调用equals方法比较属性值。

  5. 一样:不存入 不一样:存入数组,形成链表(单链表)。

    JDK8以前:新元素存入数组,老元素挂在新元素下面

    JDK8以后:新元素直接挂在老元素下面

HashSet的三个问题:

问题1:HashSet为什么存和取的顺序一样?

问题2:HashSet为什么没有索引?

问题3:HashSet是利用什么机制保证数据去重的?(HashCode方法、equals方法)

利用HashSet集合去除重复元素

需求:创建一个存储学生对象的集合,存储多个学生对象。

使用程序实现在控制台遍历集合。

要求:学生对象的成员变量值相同,我们就认为是同一个对象。

关键:学生类重写hashCode方法和equals方法即可。

标签:浅谈,HashSet,Object,哈希,Student,集合,new,HashMap
From: https://www.cnblogs.com/jundong2177/p/17237533.html

相关文章

  • Redis整数集合
    集合键的底层实现之一,当集合只包含整数值元素,且报价函的元素不多时,就会使用整数集合作为集合键的底层实现。intset实现typedefstructintset{ uint32_tencoding;//......
  • 查找手机价格低于3000(返回集合类型)
    packagecom.itheima.test;importjava.util.ArrayList;publicclassTest8{publicstaticvoidmain(String[]args){ArrayList<Phone>list=new......
  • 浅谈市政施工中深基坑支护技术施工中的难点与突破途径 方芳 武汉市江夏区公路建筑工程
    浅谈市政施工中深基坑支护技术施工中的难点与突破途径方芳武汉市江夏区公路建筑工程公司   湖北武汉    430200http://www.qikan.com.cn/newarticleinfo/828c2......
  • mybatis返回集合对象包含List<String>
    mybatis返回集合对象包含List<String>时间:2021-07-13本文章向大家介绍mybatis返回集合对象包含List<String>,主要包括mybatis返回集合对象包含List<String>使用实例、应用......
  • redis 操作集合基本操作
    Redis的Set是String类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。集合对象的编码可以是intset或者hashtable。Redis中集合是通过哈......
  • nodejs 操作redis的集合操作
    constredis=require('redis');constclient=redis.createClient();//向集合中添加元素client.sadd('myset','foo','bar','baz',(err,result)=>{cons......
  • 浅谈云原生基础入坑与docker 搭建redis-cluster集群
    浅谈云原生基础入坑与docker搭建redis-cluster集群开篇来点自己的小感触:自从走上后端开发这条无法回头的互卷道路以后,在视野内可见新的技术在迭代,更新的技术在不断发行。......
  • Collection单列集合总结
    这篇文章记录了Collection集合,List集合,Set集合在文章第七点总结了两大系列集合的五种实现类的区别,有需要的小伙伴可以直接去查看一、什么是集合集合是Java中存储对象......
  • Web API接口返回实现类集合的姿势了解
    大家好,我是沙漠尽头的狼。一.问题描述如下图,定义两个子类Student和Employ,都继承自抽象类PersonBase:publicabstractclassPersonBase{publicstringName{ge......
  • 集合(可恶啊,学的好慢,去青岛玩了5天)
    集合集合概念对象的容器,实现了对对象常用的操作,类似于数组的功能集合和数组的区别:数组长度固定,集合长度不固定数组可以存储基本类型和引用类型,集合只能引用类型Colle......