爆款云主机2核4G限时秒杀,88元/年起!
查看详情

活动

天翼云最新优惠活动,涵盖免费试用,产品折扣等,助您降本增效!
热门活动
  • 618智算钜惠季 爆款云主机2核4G限时秒杀,88元/年起!
  • 免费体验DeepSeek,上天翼云息壤 NEW 新老用户均可免费体验2500万Tokens,限时两周
  • 云上钜惠 HOT 爆款云主机全场特惠,更有万元锦鲤券等你来领!
  • 算力套餐 HOT 让算力触手可及
  • 天翼云脑AOne NEW 连接、保护、办公,All-in-One!
  • 中小企业应用上云专场 产品组合下单即享折上9折起,助力企业快速上云
  • 息壤高校钜惠活动 NEW 天翼云息壤杯高校AI大赛,数款产品享受线上订购超值特惠
  • 天翼云电脑专场 HOT 移动办公新选择,爆款4核8G畅享1年3.5折起,快来抢购!
  • 天翼云奖励推广计划 加入成为云推官,推荐新用户注册下单得现金奖励
免费活动
  • 免费试用中心 HOT 多款云产品免费试用,快来开启云上之旅
  • 天翼云用户体验官 NEW 您的洞察,重塑科技边界

智算服务

打造统一的产品能力,实现算网调度、训练推理、技术架构、资源管理一体化智算服务
智算云(DeepSeek专区)
科研助手
  • 算力商城
  • 应用商城
  • 开发机
  • 并行计算
算力互联调度平台
  • 应用市场
  • 算力市场
  • 算力调度推荐
一站式智算服务平台
  • 模型广场
  • 体验中心
  • 服务接入
智算一体机
  • 智算一体机
大模型
  • DeepSeek-R1-昇腾版(671B)
  • DeepSeek-R1-英伟达版(671B)
  • DeepSeek-V3-昇腾版(671B)
  • DeepSeek-R1-Distill-Llama-70B
  • DeepSeek-R1-Distill-Qwen-32B
  • Qwen2-72B-Instruct
  • StableDiffusion-V2.1
  • TeleChat-12B

应用商城

天翼云精选行业优秀合作伙伴及千余款商品,提供一站式云上应用服务
进入甄选商城进入云市场创新解决方案
办公协同
  • WPS云文档
  • 安全邮箱
  • EMM手机管家
  • 智能商业平台
财务管理
  • 工资条
  • 税务风控云
企业应用
  • 翼信息化运维服务
  • 翼视频云归档解决方案
工业能源
  • 智慧工厂_生产流程管理解决方案
  • 智慧工地
建站工具
  • SSL证书
  • 新域名服务
网络工具
  • 翼云加速
灾备迁移
  • 云管家2.0
  • 翼备份
资源管理
  • 全栈混合云敏捷版(软件)
  • 全栈混合云敏捷版(一体机)
行业应用
  • 翼电子教室
  • 翼智慧显示一体化解决方案

合作伙伴

天翼云携手合作伙伴,共创云上生态,合作共赢
天翼云生态合作中心
  • 天翼云生态合作中心
天翼云渠道合作伙伴
  • 天翼云代理渠道合作伙伴
天翼云服务合作伙伴
  • 天翼云集成商交付能力认证
天翼云应用合作伙伴
  • 天翼云云市场合作伙伴
  • 天翼云甄选商城合作伙伴
天翼云技术合作伙伴
  • 天翼云OpenAPI中心
  • 天翼云EasyCoding平台
天翼云培训认证
  • 天翼云学堂
  • 天翼云市场商学院
天翼云合作计划
  • 云汇计划
天翼云东升计划
  • 适配中心
  • 东升计划
  • 适配互认证

开发者

开发者相关功能入口汇聚
技术社区
  • 专栏文章
  • 互动问答
  • 技术视频
资源与工具
  • OpenAPI中心
开放能力
  • EasyCoding敏捷开发平台
培训与认证
  • 天翼云学堂
  • 天翼云认证
魔乐社区
  • 魔乐社区

支持与服务

为您提供全方位支持与服务,全流程技术保障,助您轻松上云,安全无忧
文档与工具
  • 文档中心
  • 新手上云
  • 自助服务
  • OpenAPI中心
定价
  • 价格计算器
  • 定价策略
基础服务
  • 售前咨询
  • 在线支持
  • 在线支持
  • 工单服务
  • 建议与反馈
  • 用户体验官
  • 服务保障
  • 客户公告
  • 会员中心
增值服务
  • 红心服务
  • 首保服务
  • 客户支持计划
  • 专家技术服务
  • 备案管家

了解天翼云

天翼云秉承央企使命,致力于成为数字经济主力军,投身科技强国伟大事业,为用户提供安全、普惠云服务
品牌介绍
  • 关于天翼云
  • 智算云
  • 天翼云4.0
  • 新闻资讯
  • 天翼云APP
基础设施
  • 全球基础设施
  • 信任中心
最佳实践
  • 精选案例
  • 超级探访
  • 云杂志
  • 分析师和白皮书
  • 天翼云·创新直播间
市场活动
  • 2025智能云生态大会
  • 2024智算云生态大会
  • 2023云生态大会
  • 2022云生态大会
  • 天翼云中国行
天翼云
  • 活动
  • 智算服务
  • 产品
  • 解决方案
  • 应用商城
  • 合作伙伴
  • 开发者
  • 支持与服务
  • 了解天翼云
      • 文档
      • 控制中心
      • 备案
      • 管理中心

      Set接口和常用方法+HashSet分析

      首页 知识中心 软件开发 文章详情页

      Set接口和常用方法+HashSet分析

      2023-06-01 06:42:55 阅读次数:451

      HashSet,Set,接口

      1. Set接口基本介绍  517

      1)无序(添加和取出的顺序不一致),没有索引[后面演示]

      2)不允许重复元素,所以最多包含一个null

      3) JDK API中Set接口的实现类有:

      Set接口和常用方法+HashSet分析

      2. Set 接口的常用方法

      和 List 接口一样, Set 接口也是 Collection 的子接口,因此,常用方法和 Collection 接口一样. 

      2.1 Set 接口的遍历方式  517

      同Collection的遍历方式样,因为Set接口是Collection接口的子接口。

      1.可以使用迭代器

      2.增强for

      3.不能使用索引的方式来获取.

      代码在com.stulzl.set_method.包中

      Set_Method
      package com.stulzl.set_method;
      
      import java.util.HashSet;
      import java.util.Iterator;
      import java.util.Set;
      
      //Set接口常用方法  517
      @SuppressWarnings({"all"})
      public class Set_Method {
          public static void main(String[] args) {
              //老韩解读
              //1. 以 Set 接口的实现类 HashSet 来讲解 Set 接口的方法
              //2. set 接口的实现类的对象(Set 接口对象), 不能存放重复的元素, 可以添加一个 null
              //3. set 接口对象存放数据是无序(即添加的顺序和取出的顺序不一致)
              //4. 注意:取出的顺序的顺序虽然不是添加的顺序,但是他的固定.
              Set set = new HashSet();
              set.add("john");
              set.add("lucy");
              set.add("john");//重复
              set.add("jack");
              set.add("hsp");
              set.add("mary");
              set.add(null);//
              set.add(null);//再次添加 null
              System.out.println("set="+set);
              //取10次
              for(int i = 0; i <10;i ++) {
                  System.out.println("set=" + set);
              }
      
              //遍历可以使用迭代器
              System.out.println("====使用迭代器====");
              Iterator iterator = set.iterator();
              while (iterator.hasNext()) {
                  Object obj = iterator.next();
                  System.out.println("obj="+obj);
              }
              //使用增强for
              System.out.println("====使用增强for====");
              for (Object o :set) {
                  System.out.println("o="+o);
              }
              
              //set接口对象不能通过索引来获取,因此也就不能使用普通for循环遍历
              //删除
              set.remove("jack");
              System.out.println("set="+set);
          }
      }

      3. Set 接口实现类-HashSet   518

      3.1 HashSet 的全面说明

      1) HashSet实现了 Set接口

      2) HashSet实际上是HashMap,看下源码. (图)

      Set接口和常用方法+HashSet分析

      3)可以存放null值,但是只能有一个null

      4) HashSet不保证元素是有序的,取决于hash后,再确定索引的结果(即,不

      保证存放元素的顺序和取出顺序一 致)

      5)不能有重复元素/对象.在前面Set接口使用已经讲过

      代码在com.stulzl.set_hashset.包中

      Set_HashSet
      package com.stulzl.set_hashset;
      
      import java.util.HashSet;
      import java.util.Set;
      
      //HashSet 的全面说明  518
      @SuppressWarnings({"all"})
      public class Set_HashSet {
          public static void main(String[] args) {
              //解读
              //1. 构造器走源码
              /*
              public HashSet() {
              map = new HashMap<>();
              }
              */
              //2. HashSet 可以存放 null ,但是只能有一个 null,即元素不能重复
              //不能有重复元素/对象.在前面Set接口使用已经讲过
              Set hashSet = new HashSet();
              hashSet.add(null);
              hashSet.add(null);
              System.out.println("hashSet="+hashSet);
          }
      }

      4. HashSet案例说明  深度解析其特性518

      代码在com.stulzl.hashset_exercise01.包中

      HashSet_Exercise01

      package com.stulzl.hashset_exercise01;
      
      import java.util.HashSet;
      
      //HashSet案例说明  518
      @SuppressWarnings({"all"})
      public class HashSet_Exercise01 {
          public static void main(String[] args) {
              HashSet set = new HashSet();
              //说明
              //1. 在执行 add 方法后,会返回一个 boolean 值
              //2. 如果添加成功,返回 true, 否则返回 false
      
              System.out.println(set.add("john"));//T
              System.out.println(set.add("lucy"));//T
              System.out.println(set.add("john"));//F
              System.out.println(set.add("jack"));//T
              System.out.println(set.add("Rose"));//T
              //3. 可以通过 remove 指定删除哪个对象
              set.remove("john");
              System.out.println("set=" + set);//3个 set=[Rose, lucy, jack]
      
              //逐步深入研究HashSet特性
              set = new HashSet();
              System.out.println("set="+set);//0set=[]
              //4 Hashset 不能添加相同的元素/数据
              set.add("lucy");//添加成功
              set.add("lucy");//加入不了
              set.add(new Dog("tom"));//OK
              set.add(new Dog("tom"));//Ok
              System.out.println("set=" + set);//set=[Dog{name='tom'}, lucy, Dog{name='tom'}]
      
              //再次深入,非常经典的面试题
              set.add(new String("lzl"));//ok
              set.add(new String("lzl"));//不行,看源码分析可知
              System.out.println("set="+set);
      
          }
      }
      class Dog{
          private String name;
      
          public Dog(String name) {
              this.name = name;
          }
      
          @Override
          public String toString() {
              return "Dog{" +
                      "name='" + name + '\'' +
                      '}';
          }
      }

      5. HashSet底层机制说明

      5.1 模拟简单的数组+链表结构  519

      ➢分析HashSet底层是HashMap, HashMap底层是(数组+链表+红黑树)为了让大家真正理解,模拟简单的数组+链表结构

      Set接口和常用方法+HashSet分析

      代码在com.stulzl.hashset_structure.包中

      HashSet_Structure
      package com.stulzl.hashset_structure;
      
      //模拟简单的数组+链表结构  519
      @SuppressWarnings({"all"})
      public class HashSet_Structure {
          public static void main(String[] args) {
              //模拟HashSet的底层(HashMap的底层结构)
              //1. 创建一个数组,数组的类型是 Node[]
              //2. 有些人,直接把 Node[] 数组称为 表
              Node[] table = new Node[16];
              System.out.println("table="+table);
      
              //创建一个节点将jonh放在索引为2的位置
              Node jonh = new Node("jonh",null);
              table[2] = jonh;//把jonh放在table表的索引为2的位置
              Node jack = new Node("jack", null);//在创建一个结点jack
              jonh.next = jack;//将jack结点挂载到jonh后面
              Node rose = new Node("Rose", null);
              jack.next = rose;//将Rose挂载到jack后面
              
              Node lucy = new Node("lucy", null);
              table[3] = lucy;//把Lucy放在table表的索引为3的位置
              System.out.println("table="+table);
          }
      }
      class Node{//结点 存储数据 可以指向下一个节点从而形成链表
          Object item;//存储数据
          Node next;//指向下一个结点
      
          public Node(Object item, Node next) {
              this.item = item;
              this.next = next;
          }
      }

      5.2 HashSet底层分析  520-521-522

      ➢分析HashSet的添加元素底层是如何实现(hash() + equals())先说结论,再Debug源码+图解[前方高能,非战斗人员,做好撤退准备]

      Set接口和常用方法+HashSet分析

      1. HashSet底层是HashMap

      2.添加一个元素时,先得到hash值会转成-->索引值

      3.找到存储数据表table ,看这个索引位置是否已经存放的有元素

      4.如果没有,直接加入

      5.如果有,调用equals比较,如果相同,就放弃添加,如果不相同,则挂载到最后面

      6.在Java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8),并且table的大小 > =MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

      代码在com.stulzl.hashset_source.包中

      HashSet_Source
      package com.stulzl.hashset_source;
      
      import java.util.HashSet;
      
      //HashSet底层原码分析  521-522  太复杂了,看视频解析吧
      @SuppressWarnings({"all"})
      public class HashSet_Source {
          public static void main(String[] args) {
              HashSet hashSet = new HashSet();
              hashSet.add("java");//到此位置,第1次add分析完毕.
              hashSet.add("php");//到此位置,第2次add分析完毕
              hashSet.add("java");
              System.out.println("set=" + hashSet);//set=[java, php]
              /*
              对HashSet 的源码解读
              1. 执行 HashSet()
                  public HashSet() {
                      map = new HashMap<>();
                  }
              2. 执行 add()
                 public boolean add(E e) {//e = "java"
                      return map.put(e, PRESENT)==null;//(static) PRESENT = new Object();
                 }
               3.执行 put() , 该方法会执行 hash(key) 得到key对应的hash值 算法h = key.hashCode()) ^ (h >>> 16)
                   public V put(K key, V value) {//key = "java" value = PRESENT 共享
                      return putVal(hash(key), key, value, false, true);
                  }
               4.执行 putVal
               final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                         boolean evict) {
                      Node[] tab; Node p; int n, i; //定义了辅助变量
                      //table 就是 HashMap 的一个数组,类型是 Node[]
                      //if 语句表示如果当前table 是null, 或者 大小=0
                      //就是第一次扩容,到16个空间.
                      if ((tab = table) == null || (n = tab.length) == 0)
                          n = (tab = resize()).length;
      
                      //(1)根据key,得到hash 去计算该key应该存放到table表的哪个索引位置
                      //并把这个位置的对象,赋给 p
                      //(2)判断p 是否为null
                      //(2.1) 如果p 为null, 表示还没有存放元素, 就创建一个Node (key="java",value=PRESENT)
                      //(2.2) 就放在该位置 tab[i] = newNode(hash, key, value, null)
      
                      if ((p = tab[i = (n - 1) & hash]) == null)
                          tab[i] = newNode(hash, key, value, null);
                      else {
                          //一个开发技巧提示: 在需要局部变量(辅助变量)时候,在创建
                          Node e; K k; //
                          //如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样
                          //并且满足 下面两个条件之一:
                          //(1) 准备加入的key 和 p 指向的Node 结点的 key 是同一个对象
                          //(2)  p 指向的Node 结点的 key 的equals() 和准备加入的key比较后相同
                          //就不能加入
                          if (p.hash == hash &&
                              ((k = p.key) == key || (key != null && key.equals(k))))
                              e = p;
                          //再判断 p 是不是一颗红黑树,
                          //如果是一颗红黑树,就调用 putTreeVal , 来进行添加
                          else if (p instanceof TreeNode)
                              e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
                          else {//如果table对应索引位置,已经是一个链表, 就使用for循环比较
                                //(1) 依次和该链表的每一个元素比较后,都不相同, 则加入到该链表的最后
                                //    注意在把元素添加到链表后,立即判断 该链表是否已经达到8个结点
                                //    , 就调用 treeifyBin() 对当前这个链表进行树化(转成红黑树)
                                //    注意,在转成红黑树时,要进行判断, 判断条件
                                //    if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY(64))
                                //            resize();
                                //    如果上面条件成立,先table扩容.
                                //    只有上面条件不成立时,才进行转成红黑树
                                //(2) 依次和该链表的每一个元素比较过程中,如果有相同情况,就直接break
      
                              for (int binCount = 0; ; ++binCount) {
                                  if ((e = p.next) == null) {
                                      p.next = newNode(hash, key, value, null);
                                      if (binCount >= TREEIFY_THRESHOLD(8) - 1) // -1 for 1st
                                          treeifyBin(tab, hash);
                                      break;
                                  }
                                  if (e.hash == hash &&
                                      ((k = e.key) == key || (key != null && key.equals(k))))
                                      break;
                                  p = e;
                              }
                          }
                          if (e != null) { // existing mapping for key
                              V oldValue = e.value;
                              if (!onlyIfAbsent || oldValue == null)
                                  e.value = value;
                              afterNodeAccess(e);
                              return oldValue;
                          }
                      }
                      ++modCount;
                      //size 就是我们每加入一个结点Node(k,v,h,next), size++
                      if (++size > threshold)
                          resize();//扩容
                      afterNodeInsertion(evict);
                      return null;
                  }
               */
          }
      }

      6. 分析HashSet的扩容和转成红黑树机制  523-524

      先说结论,代码演示补充说明threshold

      1. HashSet底层是HashMap, 第次添加时,table 数组扩容到16,临界值(threshold)是16*加载因子(loadFactor)是0.75 = 12

      2.如果table数组使用到了临界值12,就会扩容到16*2 = 32,新的临界值就是32*0.75 = 24,依次类推

      3.在Java8中,如果-条链表的元素个数到达TREEIFY_THRESHOLD(默认是8 ),并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树),否则仍然采用数组扩容机制

      Set接口和常用方法+HashSet分析

      代码在com.stulzl.hashset_increment.包中

      HashSetIncrement

      package com.stulzl.hashset_increment;
      
      import javax.crypto.spec.PSource;
      import java.util.HashSet;
      import java.util.Objects;
      
      //分析HashSet的扩容和转成红黑树机制  523-524
      @SuppressWarnings({"all"})
      public class HashSetIncrement {
          public static void main(String[] args) {
              /*  523
              HashSet底层是HashMap, 第一次添加时,table 数组扩容到 16,
              临界值(threshold)是 16*加载因子(loadFactor)是0.75 = 12
              如果table 数组使用到了临界值 12,就会扩容到 16 * 2 = 32,
              新的临界值就是 32*0.75 = 24, 依次类推
               */
              HashSet hashSet = new HashSet();
      //        for (int i = 0; i <= 100; i++) {
      //            hashSet.add(i);//1,2,3,4,5...100
      //        }
      
               /*  523
              在Java8中, 如果一条链表的元素个数到达 TREEIFY_THRESHOLD(默认是 8 ),
              并且table的大小 >= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树),
              否则仍然采用数组扩容机制
      
               */
      //        for(int i =1;i<=12;i++){
      //            hashSet.add(new A(i));
      //        }
      //        System.out.println("hashSet="+hashSet);
      
              /*  524
                  当我们向hashset增加一个元素,-> Node -> 加入table , 就算是增加了一个size++
              */
              for(int i = 1; i <= 7; i++) {//在table的某一条链表上添加了 7个A对象
                  hashSet.add(new A(i));//
              }
      
              for(int i = 1; i <= 7; i++) {//在table的另外一条链表上添加了 7个B对象
                  hashSet.add(new B(i));//
              }
          }
      }
      class B{
          private int B;
      
          public B(int b) {
              B = b;
          }
          @Override
          public int hashCode() {
              return 200;
          }
      }
      class A{
          private int n;
      
          public A(int n) {
              this.n = n;
          }
      
          //重写hashcode方法,保证返回的hashcode值一样从而使数据再一条链表上
          @Override
          public int hashCode() {
              return 100;
          }
      }

      7. HashSet练习  525

      重写hash值方法小提示Alt+Insert

      Set接口和常用方法+HashSet分析

      定义一个Employee类, 该类包含: private成员属性name,age要求:

      1.创建3个Employee对象放入HashSet中

      2.当name和age的值相同时,认为是相同员工,不能添加到HashSet集合中

      代码在com.stulzl.hashset_exercise01.包中

      HashSet_Exercise01

      package com.stulzl.hashset_exercise01;
      
      import java.util.HashSet;
      import java.util.Objects;
      
      //HashSet练习 525
      //定义一个Employee类, 该类包含: private成员属性name,age要求:
      //1.创建3个Employee对象放入HashSet中
      //2.当name和age的值相同时,认为是相同员工,不能添加到HashSet集合中
      @SuppressWarnings({"all"})
      public class HashSet_Exercise01 {
          public static void main(String[] args) {
              HashSet hashSet = new HashSet();
              hashSet.add(new Employee("milan",18));//ok
              hashSet.add(new Employee("smith",18));//ok
              hashSet.add(new Employee("milan",18));//no
              
              //重写hash值方法之后
              System.out.println("hashSet="+hashSet);
      
          }
      }
      class Employee{
          private String name;
          private int age;
      
          public Employee(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
      
          @Override
          public String toString() {
              return "Employee{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      '}';
          }
      
          //如果name和age相同则返回相同的hash值
      
          @Override
          public boolean equals(Object o) {
              if (this == o) return true;
              if (o == null || getClass() != o.getClass()) return false;
              Employee employee = (Employee) o;
              return age == employee.age &&
                      Objects.equals(name, employee.name);
          }
      
          @Override
          public int hashCode() {
              return Objects.hash(name, age);
          }
      }

      8. HashSet练习2  526

      //定义一个Employee类,该类包含: private成员属性name,sal,birthday(MyDate类型), 526

      // 其中birthday为MyDate类型(属性包括: year, month, day),要求:

      //1.创建3个Employee放入HashSet中

      //2.当name和birthday的值相同时,认为是相同员工,不能添加到HashSet集合中

      代码在com.stulzl.hashset_exercise02.包中

      HashSet_Exercise02

      package com.stulzl.hashset_exercise02;
      
      import java.util.HashSet;
      import java.util.Objects;
      
      //定义一个Employee类,该类包含: private成员属性name,sal,birthday(MyDate类型), 526
      // 其中birthday为MyDate类型(属性包括: year, month, day),要求:
      //1.创建3个Employee放入HashSet中
      //2.当name和birthday的值相同时,认为是相同员工,不能添加到HashSet集合中
      @SuppressWarnings({"all"})
      public class HashSet_Exercise02 {
          public static void main(String[] args) {
              HashSet hashSet = new HashSet();
              hashSet.add(new Employee("milan",1800,new MyDate(2020,5,3)));
              hashSet.add(new Employee("smith",1850,new MyDate(2021,5,3)));
              hashSet.add(new Employee("milan",1820,new MyDate(2020,5,3)));
              System.out.println("hashSet="+hashSet);
          }
      }
      class MyDate{
          private int year;
          private int month;
          private int day;
      
          public MyDate(int year, int month, int day) {
              this.year = year;
              this.month = month;
              this.day = day;
          }
      
          public int getYear() {
              return year;
          }
      
          public void setYear(int year) {
              this.year = year;
          }
      
          public int getMonth() {
              return month;
          }
      
          public void setMonth(int month) {
              this.month = month;
          }
      
          public int getDay() {
              return day;
          }
      
          public void setDay(int day) {
              this.day = day;
          }
      
          @Override
          public String toString() {
              return  year + "-" + month + "-" + day;
          }
      
          //重写birthday的equals和hash值
          @Override
          public boolean equals(Object o) {
              if (this == o) return true;
              if (o == null || getClass() != o.getClass()) return false;
              MyDate myDate = (MyDate) o;
              return year == myDate.year &&
                      month == myDate.month &&
                      day == myDate.day;
          }
      
          @Override
          public int hashCode() {
              return Objects.hash(year, month, day);
          }
      }
      class Employee{
          private String name;
          private double salary;
          private MyDate birthday;
      
          public Employee(String name, double salary, MyDate birthday) {
              this.name = name;
              this.salary = salary;
              this.birthday = birthday;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public double getSalary() {
              return salary;
          }
      
          public void setSalary(double salary) {
              this.salary = salary;
          }
      
          public MyDate getBirthday() {
              return birthday;
          }
      
          public void setBirthday(MyDate birthday) {
              this.birthday = birthday;
          }
      
          @Override
          public String toString() {
              return "Employee{" +
                      "name='" + name + '\'' +
                      ", salary=" + salary +
                      ", birthday=" + birthday +
                      '}';
          }
      
          //重写name和birthday的equals和hash值,会涉及动态绑定
          @Override
          public boolean equals(Object o) {
              if (this == o) return true;
              if (o == null || getClass() != o.getClass()) return false;
              Employee employee = (Employee) o;
              return name.equals(employee.name) &&
                      birthday.equals(employee.birthday);
          }
      
          @Override
          public int hashCode() {
              return Objects.hash(name, birthday);
          }
      }

      9. Set 接口实现类-LinkedHashSet  527

      9.1 LinkedHashSet 的全面说明  527

      1) LinkedHashSet是HashSet的子类

      Set接口和常用方法+HashSet分析

      2) LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双

      向链表

      3) LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序(图),这使得元素看起来是以插入顺序保存的。

      4) LinkedHashSet不允许添重复元素

      3.2 LinkedHashSet底层  528

      Set接口和常用方法+HashSet分析

      说明

      1)在LinkedHastSet 中维护了一个hash表和双向链表( LinkedHashSet有head和tail )

      2)每一个节点有before和after属性,这样可以形成双向链表

      3)在添加一个元素时,先求hash值,在求索引确定该元素在table的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加[原则和hashset一样])

      tail.next = newElement //示意代码

      newElement.pre = tail

      tail = newEelment;

      4)这样的话,我们遍历LinkedHashSet也能确保插入顺序和遍历顺序一致

      代码在com.stulzl.linkedhashset_source.包中

      linkedhashset_source
      package com.stulzl.linkedhashset_source;
      
      import java.util.LinkedHashSet;
      import java.util.Set;
      
      //LinkedHashSet_Source底层源码  528 看视频
      @SuppressWarnings({"all"})
      public class LinkedHashSet_Source {
          public static void main(String[] args) {
              //分析一下LinkedHashSet的底层机制
              Set set = new LinkedHashSet();
              set.add(new String("AA"));
              set.add(456);
              set.add(456);
              set.add(new Customer("刘", 1001));
              set.add(123);
              set.add("HSP");
      
              System.out.println("set=" + set);
              //解读
              //1. LinkedHashSet 加入顺序和取出元素/数据的顺序一致
              //2. LinkedHashSet 底层维护的是一个LinkedHashMap(是HashMap的子类)
              //3. LinkedHashSet 底层结构 (数组table+双向链表)
              //4. 添加第一次时,直接将 数组table 扩容到 16 ,存放的结点类型是 LinkedHashMap$Entry
              //5. 数组是 HashMap$Node[] 存放的元素/数据是 LinkedHashMap$Entry类型
              /*
                      //继承关系是在内部类完成.
                      static class Entry extends HashMap.Node {
                          Entry before, after;
                          Entry(int hash, K key, V value, Node next) {
                              super(hash, key, value, next);
                          }
                      }
      
               */
          }
      }
      class Customer {
          private String name;
          private int no;
      
          public Customer(String name, int no) {
              this.name = name;
              this.no = no;
          }
      
          @Override
          public String toString() {
              return "Customer{" +
                      "name='" + name + '\'' +
                      ", no=" + no +
                      '}';
          }
      }

      10. LinkedHashSet 课后练习题  529

      Car类(属性:name,price),如果 name和price一一样,

      则认为是相同元素,就不能添加。

      代码在com.stulzl.linkedhashset_exercise01.包中

      LinkedHashSet_Exercise01

      package com.stulzl.linkedhashset_exercise01;
      
      import java.util.LinkedHashSet;
      import java.util.Objects;
      
      //Car类(属性:name,price),如果 name和price一样,  529
      //则认为是相同元素,就不能添加。
      @SuppressWarnings({"all"})
      public class LinkedHashSet_Exercise01 {
          public static void main(String[] args) {
              LinkedHashSet linkedHashSet = new LinkedHashSet();
              linkedHashSet.add(new Car("奥拓", 1000));//OK
              linkedHashSet.add(new Car("奥迪", 300000));//OK
              linkedHashSet.add(new Car("法拉利", 10000000));//OK
              linkedHashSet.add(new Car("奥迪", 300000));//加入不了
              linkedHashSet.add(new Car("保时捷", 70000000));//OK
              linkedHashSet.add(new Car("奥迪", 300000));//加入不了
              System.out.println("linkedHashSet="+linkedHashSet);
      
          }
      }
      class Car{
          private String name;
          private double price;
      
          public Car(String name, double price) {
              this.name = name;
              this.price = price;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public double getPrice() {
              return price;
          }
      
          public void setPrice(double price) {
              this.price = price;
          }
      
          @Override
          public String toString() {
              return "\nCar{" +
                      "name='" + name + '\'' +
                      ", price=" + price +
                      '}';
          }
      
          //重写hash值和equals方法
          //当 name 和 price 相同时, 就返回相同的 hashCode 值, equals返回t
      
          @Override
          public boolean equals(Object o) {
              if (this == o) return true;
              if (o == null || getClass() != o.getClass()) return false;
              Car car = (Car) o;
              return Double.compare(car.price, price) == 0 &&
                      Objects.equals(name, car.name);
          }
      
          @Override
          public int hashCode() {
              return Objects.hash(name, price);
          }
      }
      版权声明:本文内容来自第三方投稿或授权转载,原文地址:https://blog.51cto.com/u_15784725/6290303,作者:进击的菜鸟子,版权归原作者所有。本网站转在其作品的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如因作品内容、版权等问题需要同本网站联系,请发邮件至ctyunbbs@chinatelecom.cn沟通。

      上一篇:线程的生命周期,同步和锁

      下一篇:JUint

      相关文章

      2025-05-14 10:33:25

      超级好用的C++实用库之网络

      在网络相关的项目中,我们经常需要去获取和设置设备的IP地址、子网掩码、网关地址、MAC地址等信息。这些信息一般与操作系统相关,在Windows系统和Linux系统上调用的接口是不一样的。

      2025-05-14 10:33:25
      Linux , 参数 , 地址 , 接口 , 网卡 , 返回值
      2025-05-14 09:51:15

      JAVA 两个类同时实现同一个接口

      在Java中,两个类同时实现同一个接口是非常常见的。接口定义了一组方法,实现接口的类必须提供这些方法的具体实现。

      2025-05-14 09:51:15
      Lambda , 函数 , 实现 , 接口 , 方法 , 表达式
      2025-05-13 09:49:12

      Java学习(动态代理的思想详细分析与案例准备)(1)

      Java学习(动态代理的思想详细分析与案例准备)(1)

      2025-05-13 09:49:12
      java , 代理 , 代码 , 对象 , 接口 , 方法 , 需要
      2025-05-09 09:30:05

      WebAPi接口安全之公钥私钥加密

      WebAPi接口安全之公钥私钥加密

      2025-05-09 09:30:05
      加密 , 参数 , 接口 , 请求 , 重写
      2025-05-09 08:50:35

      springboot实战学习(11)(更新用户基本信息接口主逻辑)

      springboot实战学习(11)(更新用户基本信息接口主逻辑)

      2025-05-09 08:50:35
      接口 , 方法 , 更新 , 用户 , 请求
      2025-05-09 08:50:35

      springboot实战学习(1)(开发模式与环境)

      springboot实战学习(1)(开发模式与环境)

      2025-05-09 08:50:35
      依赖 , 前端 , 后端 , 开发 , 接口 , 数据库 , 文档
      2025-05-08 09:03:29

      装饰者设计模式(一)

      装饰者设计模式(一)

      2025-05-08 09:03:29
      接口 , 目标 , 装饰 , 设计模式 , 返回值
      2025-05-08 09:03:29

      Java序列化有什么作用

      对java对象进行序列化之后,会变成字节码,这样就会比较方便在网络上进行传输,也可以在磁盘上进行存储。

      2025-05-08 09:03:29
      对象 , 序列化 , 接口 , 构造函数
      2025-05-08 09:03:07

      spring AOP 代理模式

      spring AOP 代理模式

      2025-05-08 09:03:07
      代理 , 动态 , 接口 , 模式
      2025-05-07 09:09:26

      springboot系列教程(二十五):springboot整合ElasticSearch,实现高性能搜索引擎

      ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java开发的,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。

      2025-05-07 09:09:26
      ElasticSearch , springboot , 接口 , 搜索引擎
      查看更多
      推荐标签

      作者介绍

      天翼云小翼
      天翼云用户

      文章

      33561

      阅读量

      5249739

      查看更多

      最新文章

      超级好用的C++实用库之网络

      2025-05-14 10:33:25

      JAVA 两个类同时实现同一个接口

      2025-05-14 09:51:15

      Java学习(动态代理的思想详细分析与案例准备)(1)

      2025-05-13 09:49:12

      WebAPi接口安全之公钥私钥加密

      2025-05-09 09:30:05

      springboot实战学习(11)(更新用户基本信息接口主逻辑)

      2025-05-09 08:50:35

      springboot实战学习(1)(开发模式与环境)

      2025-05-09 08:50:35

      查看更多

      热门文章

      JAVA__接口的作用

      2023-04-18 14:14:13

      什么是api接口

      2023-03-22 09:03:21

      kotlin匿名内部类与接口实现

      2023-04-18 14:15:13

      Go 语言入门很简单 -- 13. Go 接口 #私藏项目实操分享#

      2023-04-21 03:11:48

      SpringBoot写的后端API接口如何写得更优雅

      2023-06-15 06:37:47

      ts重点学习47-接口与类型别名得异同笔记

      2023-03-16 06:47:13

      查看更多

      热门标签

      java Java python 编程开发 代码 开发语言 算法 线程 Python html 数组 C++ 元素 javascript c++
      查看更多

      相关产品

      弹性云主机

      随时自助获取、弹性伸缩的云服务器资源

      天翼云电脑(公众版)

      便捷、安全、高效的云电脑服务

      对象存储

      高品质、低成本的云上存储服务

      云硬盘

      为云上计算资源提供持久性块存储

      查看更多

      随机文章

      项目平台之测试报表的编码实现(六)

      什么是api接口

      Java中的动态代理机制:原理与应用

      Nginx查找耗时的接口

      JAVA 两个类同时实现同一个接口

      Java接口详解

      • 7*24小时售后
      • 无忧退款
      • 免费备案
      • 专家服务
      售前咨询热线
      400-810-9889转1
      关注天翼云
      • 旗舰店
      • 天翼云APP
      • 天翼云微信公众号
      服务与支持
      • 备案中心
      • 售前咨询
      • 智能客服
      • 自助服务
      • 工单管理
      • 客户公告
      • 涉诈举报
      账户管理
      • 管理中心
      • 订单管理
      • 余额管理
      • 发票管理
      • 充值汇款
      • 续费管理
      快速入口
      • 天翼云旗舰店
      • 文档中心
      • 最新活动
      • 免费试用
      • 信任中心
      • 天翼云学堂
      云网生态
      • 甄选商城
      • 渠道合作
      • 云市场合作
      了解天翼云
      • 关于天翼云
      • 天翼云APP
      • 服务案例
      • 新闻资讯
      • 联系我们
      热门产品
      • 云电脑
      • 弹性云主机
      • 云电脑政企版
      • 天翼云手机
      • 云数据库
      • 对象存储
      • 云硬盘
      • Web应用防火墙
      • 服务器安全卫士
      • CDN加速
      热门推荐
      • 云服务备份
      • 边缘安全加速平台
      • 全站加速
      • 安全加速
      • 云服务器
      • 云主机
      • 智能边缘云
      • 应用编排服务
      • 微服务引擎
      • 共享流量包
      更多推荐
      • web应用防火墙
      • 密钥管理
      • 等保咨询
      • 安全专区
      • 应用运维管理
      • 云日志服务
      • 文档数据库服务
      • 云搜索服务
      • 数据湖探索
      • 数据仓库服务
      友情链接
      • 中国电信集团
      • 189邮箱
      • 天翼企业云盘
      • 天翼云盘
      ©2025 天翼云科技有限公司版权所有 增值电信业务经营许可证A2.B1.B2-20090001
      公司地址:北京市东城区青龙胡同甲1号、3号2幢2层205-32室
      • 用户协议
      • 隐私政策
      • 个人信息保护
      • 法律声明
      备案 京公网安备11010802043424号 京ICP备 2021034386号