刚学Java的小伙伴经常会困惑:HashSet
和HashMap
名字里都有"Hash",到底有啥不一样?什么时候该用哪个?今天就用最通俗的例子,带你搞懂这两个常用集合类的核心区别,看完再也不会用错啦!
一、先打个比方:它们像生活中的什么?
-
HashSet:像一个“去重的盒子”,只能装单个元素,而且自动帮你去掉重复的。
比如:往盒子里放“苹果”“香蕉”“苹果”,最后盒子里只剩“苹果”和“香蕉”。 -
HashMap:像一本“字典”,每个元素都是“单词+解释”的组合(键+值),通过“单词”能快速查到“解释”。
比如:存“apple=苹果”“banana=香蕉”,通过“apple”就能立刻找到“苹果”。
二、核心区别1:存的数据类型不一样
1. HashSet:存“单个元素”,不允许重复
- 存储形式:只存一个值(比如
String
、Integer
或自定义对象),每个元素唯一(重复元素会被自动忽略)。 - 代码示例:
HashSet<String> set = new HashSet<>(); set.add("张三"); set.add("李四"); set.add("张三"); // 重复,不会被存入 System.out.println(set.size()); // 输出2(只有两个不同元素)
2. HashMap:存“键值对”,键不能重复,值可以重复
- 存储形式:每个元素是
key-value
对,通过key
找value
,类似“索引+数据”的关系。 - 代码示例:
HashMap<String, Integer> map = new HashMap<>(); map.put("张三", 18); // 键是“张三”,值是18 map.put("李四", 20); map.put("张三", 22); // 键重复,会覆盖之前的值(18→22) System.out.println(map.get("张三")); // 输出22(最新值)
三、核心区别2:底层其实是“一家人”!
你可能想不到:HashSet的底层其实就是HashMap!
- HashSet的每个元素,其实是作为HashMap的“键”存在的,而值统一用一个默认的对象(
private static final Object PRESENT = new Object();
)。 - 所以:
- HashSet的去重逻辑,其实就是HashMap“键不能重复”的特性;
- HashSet的其他操作(添加、删除、查询),本质上都是调用HashMap的对应方法。
四、其他关键区别:一张表对比清楚
特性 | HashSet | HashMap |
---|---|---|
存储结构 | 单个元素(值) | 键值对(key-value) |
是否允许重复 | 元素不可重复(自动去重) | 键不可重复,值可重复 |
是否允许null | 允许1个null元素 | 允许1个null键,多个null值 |
常用方法 | add() 、contains() 、size() | put() 、get() 、entrySet() |
本质 | 底层是HashMap(只用键,值固定) | 独立的键值对存储结构 |
典型场景 | 去重、判断元素是否存在(如黑名单) | 快速通过“键”查“值”(如用户ID查信息) |
五、什么时候该选谁?举几个例子
1. 选HashSet的场景:
- 去重需求:比如统计用户输入过哪些不重复的关键词。
HashSet<String> keywords = new HashSet<>(); keywords.add("Java"); keywords.add("Java"); // 无效,自动去重
- 判断元素是否存在:比如检查一个用户名是否已注册(比List快100倍!)。
if (users.contains("admin")) { System.out.println("用户名已存在"); }
2. 选HashMap的场景:
- 键值对映射:比如存储学生学号和成绩,通过学号快速查成绩。
HashMap<String, Integer> scores = new HashMap<>(); scores.put("S001", 90); System.out.println("S001的成绩是:" + scores.get("S001"));
- 分组统计:比如统计每个单词出现的次数。
String text = "apple banana apple orange"; String[] words = text.split(" "); HashMap<String, Integer> countMap = new HashMap<>(); for (String word : words) { countMap.put(word, countMap.getOrDefault(word, 0) + 1); } // 结果:apple=2, banana=1, orange=1
六、零基础也能懂的底层原理
1. 为什么它们都叫“Hash”?
因为它们都用了“哈希表”(Hash Table)结构:
- 通过哈希函数把元素“计算”到一个固定位置存储,查询时直接通过哈希值定位,速度极快(平均O(1)时间)。
2. 遇到重复怎么办?
- HashSet:如果添加重复元素,会发现“键”已经存在,直接忽略;
- HashMap:如果插入重复的键,会用新的值覆盖旧值(就像字典里同一个单词被重新解释)。
七、总结:一句话分清两者
- HashSet:“去重的单身集合”,只存单个元素,自动去重,适合判断“有没有”;
- HashMap:“配对的情侣集合”,存键值对,通过键快速找值,适合“根据XX查XX”。
下次遇到需要“去重”或“键值映射”的场景,再也不用担心选错啦!如果还有疑问,欢迎在评论区留言~ 😊