• list集合去重_谈谈Java中Set集合去重的原理


    来自:https://blog.csdn.net/weixin_39527768/article/details/110826637

    =======================================================================

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

     

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

    4a696c876ac002634b16f53aa3269b44.png

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

    3e290f352dda2d64d16d4f5c91adec22.png

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

    f86ff31efdfa7336ce34607a69025a5f.png

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

    46d60de19194f5131ad013f2eeb0f58b.png

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

    f9e2c0ee1db8210d8eec97bc09156418.png

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

    aa72dc8edd1b77143bad86f3ff3da855.png
    4ae0554ff396a4420825bb187d49deaa.png

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

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

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

    53d42b373c0356a9ad708f6000d973be.png

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

    23d57aac674a66020769a82b155014ce.png

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

    50c8539327034c2fd8be7682ff3d6812.png

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

    0038d1307fa94a44e2c216d15ef66ccf.png

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

    8543dd4ec6e96321ec64490c4ef41d79.png

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

    54b52b6132a56472e4729b42bba3d7d8.png

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

    5945c9eac4b7cca836651c7cb2c4b23f.png

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

    e4219cee10b8004c9de070520d44a9db.png

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

    994fe111b375f981739742da9a54853b.png

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

    dab7ac8e4ec32e202628e673f7f7d3b2.png

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

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

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

    5c8fc458256122a5750a1ff2983d9046.png

    总结

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

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

  • 相关阅读:
    Redis 分区
    利用phpexcel把excel导入数据库和数据库导出excel实现
    Phpcms V9网站从本地上传到服务器需要修改的地方
    PHPcms怎么调用二级栏目
    phpcms调用一级栏目和二级栏目
    [v9] 列表页 调用 正文内容 或 自定义 字段(moreinfo的调用方法)
    phpcms v9最常用的22个调用代码
    phpcms_v9 多图字段 内容页,首页,分页自定义字段调用
    JS常用语句
    phpcms v9中调用栏目及调用多个子栏目中的文章列表
  • 原文地址:https://www.cnblogs.com/del88/p/16139835.html
Copyright © 2020-2023  润新知