博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个有趣的问题: 如何用HashSet来存储重复的字符串?
阅读量:7080 次
发布时间:2019-06-28

本文共 2770 字,大约阅读时间需要 9 分钟。

有一种学得快的方法,就是不要一次学太多。

1. 前言

今天,我们来探讨一个实际中不常用但却比较有意思的问题。它能帮助你理解 “HashSet中的键值是唯一的,不可重复的” 这句话的真正含义,也考验你对问题的思考深度。

注:实际应用中,我们一般是用 ArrayList 集合来存储相同的字符串的,不会用 HashSet 来存。

我们平时都看到或听说 HashSet 是不能用来存放重复的字符串的,是真的存放不了吗?如果面试问你这个问题,你能给出解决方案吗?

2. 参考解答

先给出参考解答,然后我们再来分析为什么。

解答:

虽然我们不能用 HashSet 来存放 String 类型重复的字符串,但我们可以用 HashSet 来存储 StringBuilder 类型重复的字符串呀。

public class HashSetTest {    public static void main(String[] args){        // 用 HashSet 来存放 String 类型的重复的字符串会发生什么?        HashSet
hs1 = new HashSet<>(); String s1 = new String("aaa"); String s2 = new String("aaa"); String s3 = new String("aaa"); hs1.add(s1); hs1.add(s2); hs1.add(s3); System.out.println("hs1:"+hs1); // 重复的字符串是存不进去的 // 用 HashSet 来存放 StringBuilder 类型的重复的字符串又会发生什么? HashSet
hs2 = new HashSet<>(); StringBuilder sb1 = new StringBuilder("aaa"); StringBuilder sb2 = new StringBuilder("aaa"); StringBuilder sb3 = new StringBuilder("aaa"); hs2.add(sb1); hs2.add(sb2); hs2.add(sb3); System.out.println("hs2:"+hs2); // 咦,结果发现重复的字符串也能存进去了 // 那为什么呢?我们来打印一个各个对象的hashCode看一下 System.out.println("s1的hashCode:"+s1.hashCode()); System.out.println("s2的hashCode:"+s2.hashCode()); System.out.println("s3的hashCode:"+s3.hashCode()); System.out.println("sb1的hashCode:"+sb1.hashCode()); System.out.println("sb2的hashCode:"+sb2.hashCode()); System.out.println("sb3的hashCode:"+sb3.hashCode()); }}

输出结果:

hs1:[aaa]hs2:[aaa, aaa, aaa]s1的hashCode:96321s2的hashCode:96321s3的hashCode:96321sb1的hashCode:356573597sb2的hashCode:1735600054sb3的hashCode:21685669

从打印结果来看,我们是不能用 HashSet 来存放 String 类型的重复字符串的(如hs1),但我们是可以用HashSet来存放 StringBuilder 类型的重复字符串。

3. 为什么?

从打印的 hashCode 来看,String 类型,相同字符串的不同 String 对象哈希值是一样的。而对于 StringBuilder 类型,相同字符串的不同对象哈希值是不同的。

要知道这个问题的答案,我们首先得了解 Java 虚拟机是如何判断两个对象是否相同的。

那 Java 虚拟机是如何判断两个对象是否相同的呢?

参考解答:

Java 虚拟机会先判断两个对象的 hashCode 是否相同,如果 hashCode 不同,则说明肯定是两个不同的对象了;如果 hashCode 相同再通过 equals() 方法进行进一步比较,如果 equals 方法返回 true,则说明两个对象是相同的,如果equals方法返回 false 说明两个对象不同。

具体验证思路如果你感兴趣,请查看:

那为什么相同字符串的不同 String 对象哈希值是一样的,而且还被虚拟机判断为相同的对象了呢?

因为 String 类复写了 Object 类的 hashCode() 和 equals() 方法,并实现了自己的 hashCode 值生成算法和 equals 的比较规则,具有相同字符串内容的不同 String 对象在初始化时生成的 hashCode 值是一样的,并且 String 类 equals() 方法比较的是两个字符串的内容,而不是内存地址值,这两个条件同时成立, 这就使 Java 虚拟机把具有相同内容的不同 String 对象判断为相同的对象了,就不会存入 HashSet 集合中。

而 StringBuilder 为什么就可以呢?它相同内容的不同对象的哈希值值为什么是不同的?

查看 StringBuilder 类的源码你会发现,因为 StringBuilder 并没有复写 Object 类的 hashCode() 方法和 equals() 方法,StringBuilder 用的是父类 Object 类的 hashCode 生成算法,也就是用 native 层的 hashCode 生成算法,很大概率产生的哈希值是不一样的,即使产生了一样的哈希值,Object 类的 equals() 方法比较的是两个对象的内存地址,而不是两个对象的内容,这就使 Java 虚拟机把具有相同内容的 StringBuilder 对象判断为不同的对象,就可以存入 HashSet 集合中了。

转载地址:http://xcvml.baihongyu.com/

你可能感兴趣的文章
pyton全栈开发从入门到放弃之数据类型与变量
查看>>
nessus 插件更新
查看>>
Teradata基础教程中的数据库试验环境脚本
查看>>
html+css
查看>>
cocos2d-x 数据存储
查看>>
iproute2
查看>>
js对数组的操作
查看>>
python 安装surprise库解决 c++tools错误问题
查看>>
java 练习题
查看>>
【题解】【排列组合】【回溯】【Leetcode】Generate Parentheses
查看>>
spring注解第07课 @Valid和@Validated的总结区分
查看>>
使用apache自带的压力测试工具
查看>>
PAT 1090 Highest Price in Supply Chain[较简单]
查看>>
手机web——自适应网页设计
查看>>
away3d 4.1 alpha 教程 换装篇 <3> 人物动态换装DEMO
查看>>
《你必须知道的.NET》--is和as(Ⅰ)
查看>>
VueJs组件prop验证简单理解
查看>>
leetcode703
查看>>
GDAL的安装和配置(编译proj.4)
查看>>
Swagger2使用记录
查看>>