导读:Java中Set接口是Collectio的子接口,Set集合不允许包含相同的元素。如果添加相同的元素, add()会返回FALSE, 新元素不会加入。Set集合常用于元素为数字、字符串去重等,但是当元素为自定义对象类型时,Set去重是否与我们预计一致?下面将以HashSet为例,通过一系列试验来一步步验证。

 

1、先建立一个FootBallPlayer足球运动员类

2、(假设:HashSet会把属性值全相同的对象认定为重复),为了测试HashSet对对象去重效果与猜想是否一致,我们先构建三个对象实例,其中构造两个属性一致的“C罗”。

结果:HashSet并没有认定两个“C罗”对象重复,三个实例都加入到了HashSet集合中。

3、在了解HashSet如何进行去重之前,先看看HashSet是怎么实现的。通过查看JDK源码发现HashSet内部其实是对HashMap进行操作。

4、继续查看hashSet的add()方法,其实是调用了HashMap的put()方法

5、继续追踪,直到putVal()方法(重点)

仔细看putVal()方法,发现其对于新入的元素是否重复判断依据为以下两种

  • 判断hash值是否相等,既通过判断hashCode()方法
  • 判断是否相等,通过equals()方法

6、了解了两个判断条件后,我们先做一个简单实验,既调用Integer 、String 、Object等对象equals()方法进行对比

结果发现,自定义Object对象equals返回的值为false。接下来我们逐一看看它们的equals实现方式

6.1、Integer对象的equals实现,通过阅读代码发现是判断依据是值是否相等。

6.2、String对象的equals实现,其判断的依据为:先判断引用的对象是否是同一个,再逐个对比其字符串的值

6.3 而Object的判断依据为引用的对象是否是同一个,由于上面的两位足球运动员都是新new出来的,非同一个对象,所以equlas()返回结果为false

7、看完了equlas的实现,接下来看看Integer String Object的hashCode实现。同样先做一个简单的测试,调用它们的hashCode()方法计算出hash值进行对比

实验为结果两个Object对象的hash值并不相等,接下来我们看看它们对于hashcode()的具体实现

7.1 通过源码发现 Integer是通过对其value值来进运算行得到hash值。

7.2 String也是通过对其value值来进计算行得到hash值,所以测试中结果为true

7.3 当查看Object的hashCode()方法时发现并无具体实现,通过查阅资料得知,JDK8的默认hashCode的计算是交给C++实现的,方法是通过和当前线程有关的一个随机数+三个确定值,运用Marsaglia's
xorshifschema随机数算法得到的一个随机数。所以两个不同的对象得到的hash值便不相同,测试结果也为false。(对于Object的hashCode()这里不做深入讨论,如果过深入了解的朋友也欢迎分享)

8、得知了HashSet是通过hashcode()与equals()来进行去重,且自定义Object对象的equals()和hashcode()实现原理,那么要实现HashSet按照我们期望的方式,当两个对象所有属性的值一致时认定为同一个对象,我们可以对FootBallPlayer类的equals()和hashcode()进行重写,代码如下

  • hashCode() 重写为hash值是通过对对象所有属性的值进行运算得出。
  • equals() 重写为先判断引用的对象是否是同一个,再判断对象每一个属性值是否相等

9、重写完方法,我们再重新执行一开始的程序,还是同样的三个足球运动员实例。结果与期望相同,HashSet对“C罗”对象进行了去重处理。

总结

HashSet的底层是对HashMap的操作,其去重的原理通过hashCode()与equals()方法来判断是否重复。通过实验发现自定义对象没有成功去重的原因与JDK默认的Object对象hashCode()和equals()实现有关。对于自定义对象的去重,我们可以通过重写自定义对象的hashCode()与equals()使其按照我们所想要的规则进行去重操作。

感谢您的阅读,如果喜欢本文欢迎关注和转发,本头条号将坚持原创,持续分享IT技术知识。对于文章内容有其他想法或意见建议等,欢迎提出共同讨论共同进步

list集合去重_谈谈Java中Set集合去重的原理的更多相关文章

  1. 谈谈Java中的集合

    对于集合类,主要需要掌握的就是它的内部结构,以及遍历集合的迭代模式. 接口:Collection Collection是最基本的集合接口,一个Collection代表一组Object,即Collect ...

  2. 谈谈Java中的集合list、set、map之间的区别

    参考文献:https://www.cnblogs.com/IvesHe/p/6108933.html 我这里只总结其区别,具体的说明,请查看参考文献,讲的很详细. A.list接口,实现子类有:arr ...

  3. Java中的集合概述

    Java中的集合类有两个重要的分支,分别是接口Collection(包括List,Set等)和接口Map. 由于HashSet的内部实现原理使用了HashMap,所以我们先来了解Map集合类. 1.H ...

  4. 谈谈JAVA中的安全发布

    谈谈JAVA中的安全发布 昨天看到一篇文章阐述技术类资料的"等级",看完之后很有共鸣.再加上最近在工作中越发觉得线程安全性的重要性和难以捉摸,又掏出了<Java并发编程实战& ...

  5. JAVA中的集合容器操作类

    目录 JAVA中的集合容器操作类 List集合 ArrayList的操作方法说明 LinkedList Stack Set Map Queue 总结 JAVA中的集合容器操作类 Java容器类库总共分 ...

  6. Java 中的集合接口——List、Set、Map

    Java 中的集合接口——List.Set.Map 什么叫集合:集合就是Java API所提供的一系列类的实例,可以用于动态存放多个对象.这跟我们学过的数组差不多,那为什么我们还要学集合,我们看看数组 ...

  7. 实现java 中 list集合中有几十万条数据,每100条为一组取出

    解决"java 中 list集合中有几十万条数据,每100条为一组取出来如何实现,求代码!!!"的问题. 具体解决方案如下: /** * 实现java 中 list集合中有几十万条 ...

  8. java中对集合对象list的几种循环访问

    java中对集合对象list的几种循环访问的总结如下 1 经典的for循环 public static void main(String[] args) { List<String> li ...

  9. 菜鸟日记之 java中的集合框架

    java中的集合框架图 如图所示:java中的集合分为两种Collection和Map两种接口 可分为Collection是单列集合和Map的双列集合 Collection单列集合:继承了Iterat ...

  10. C#与java中的集合区别

    集合一般的操作       插入: add       删除: remove       查找: contains,remove java中的集合 注意哪些是接口,哪些是实现类 使用集合的时候 1. ...

随机推荐

  1. Redhat5 和Redhat6安装oracle11g

    oralce安装本人认为最麻烦的就是oracle包的版本和oracle的依赖的包的问题,这个做不好后期安装过程就会出现很多诡异的问题,这里总结一下Redhat5 和Redhat6安装oracle11g ...

  2. SpringBoot 动态数据源

    SpringBoot 实现动态数据源切换 Spring Boot + Mybatis Plus + Druid + MySQL 实现动态数据源切换及动态 SQL 语句执行. 项目默认加载 applic ...

  3. JVM简单概述

    一.内存模型&分区 Java虚拟机在运行Java程序时,会管理着一块内存区域:运行时数据区 在运行时数据区里,会根据用途进行划分为以下模块: 1.Java虚拟机栈 2.本地方法栈 3.Java ...

  4. CoinBase是什么?

    什么是CoinBase交易? 比特币区块链上的每个区块中都会包含一个或者多个交易(transaction),其中第一个交易就叫做CoinBase交易. 什么是CoinBase交易? CoinBase交 ...

  5. 浅谈 Docker 网络:单节点单容器

    1.Docker 网络模型 Docker 在 1.7 版本中将容器网络部分代码抽离出来作为 Docker 的网络库,叫 libnetwork.libnetwork 中使用 CNM(Container ...

  6. C++编译器选择是否自动生成代码的背后逻辑

    C++编译器选择是否自动生成代码的背后逻辑 编译器会为class和struct(实际上两者在C++中是一回事)自动生成构造函数.赋值操作符函数和析构函数.如果不是这样,那么开发者就必须自己写一些枯燥冗 ...

  7. Clickhouse执行处理查询语句(包括DDL,DML)的过程

    Clickhouse执行处理查询语句(包括DDL,DML)的过程 总体过程 启动线程处理客户端接入的TCP连接: 接收请求数据,交给函数executeQueryImpl()处理: executeQue ...

  8. 基于React开发的chatgpt网页版(仿chatgpt)

    在浏览github的时候发现了一个好玩的项目本项目,是github大神Yidadaa开发的chatgpt网页版,该开源项目是跨平台的,Web / PWA / Linux / Win / MacOS都可 ...

  9. 25-IP核简介

    1.IP IP(Intellectual Property)即知识产权,在半导体产业中讲IP核定义为用于"ASIC或FPGA中的预先设计好的电路功能模块".简言之,这里的IP即电路 ...

  10. 浏览器兼容 : IE 5 到 IE 9

    <!--[if IE]> <link href="ie.css" rel="stylesheet"> <![endif]--> ...