您的位置:首页 > 其它

Hashset源码分析

2020-03-12 18:11 120 查看
# 1. 概述 Hashset 实现 set 接口,底层基于 Hashmap 实现, 但与 Hashmap 不同的实 Hashmap 存储键值对,Hashset 仅存储对象。 HashSet 使用成员对象来计算 hashcode 值。 # 2. 原理 在《Head fist java》一书中有描述: 当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他加入的对象的 hashcode 值作比较,如果没有相符的 hashcode,HashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,则覆盖旧元素。 这里看到很多文章说: ~~如果 equals()方法相等,HashSet 就不会让加入操作成功~~。根据 hashmap 的 put()方法源码可知,实际上是覆盖操作,虽然覆盖对象的 key 和 value 都完全一致。 **hashCode()与 equals()的相关规定:** - 如果两个对象相等,则 hashcode 一定也是相同的 - 两个对象相等,对两个 equals 方法返回 true - 两个对象有相同的 hashcode 值,它们也不一定是相等的 - 综上,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖 - hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)。 **==与 equals 的区别** - ==是判断两个变量或实例是不是指向同一个内存空间 equals 是判断两个变量或实例所指向的内存空间的值是不是相同 - ==是指对内存地址进行比较 equals()是对字符串的内容进行比较 - ==指引用是否相同 equals()指的是值是否相同 # 3. 源码分析 首先查看下源码结构,发现该类源码相对比较简单 ![](https://gitee.com/idea360/oss/raw/master/images/hashset-method-all.png) ## 3.1 构造方法 ```java /** * Constructs a new, empty set; the backing HashMap instance has * default initial capacity (16) and load factor (0.75). */ // 内部存储在hashmap中 public HashSet() { map = new HashMap<>(); } ``` ## 3.2 添加元素 add() ```java private static final Object PRESENT = new Object(); public boolean add(E e) { return map.put(e, PRESENT)==null; } ``` 可以看到添加的对象直接作为 Hashmap 的 key, 而 value 是 final 修饰的空对象。 根据之前对 [Java 面试必问之 Hashmap 底层实现原理(JDK1.8)](https://mp.weixin.qq.com/s/ugBm-koApBRepbSQ2kiV2A) 中 `put()` 方法的解读可以知道: 在 Hashmap 中首先根据 hashCode 寻找数组 bucket,当 hash 冲突时,需要比较 key 是否相等,相等则覆盖,否则通过拉链法进行处理。在 Hashset 中存储的对象作为 key,所以存储对象需要重写 `hashCode()` 和 `equals()` 方法。 # 4. 使用案例分析 ## 4.1 存储字符串案例 再来看一组示例 ```java public class Demo2 { public static void main(String[] args) { HashSet
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: