一个有趣的问题: 如何用HashSet来存储重复的字符串?

栏目: Java · 发布时间: 5年前

内容简介:今天,我们来探讨一个实际中不常用但却比较有意思的问题。它能帮助你理解 “HashSet中的键值是唯一的,不可重复的” 这句话的真正含义,也考验你对问题的思考深度。注:实际应用中,我们一般是用 ArrayList 集合来存储相同的字符串的,不会用 HashSet 来存。我们平时都看到或听说 HashSet 是不能用来存放重复的字符串的,是真的存放不了吗?如果面试问你这个问题,你能给出解决方案吗?

1. 前言

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

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

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

2. 参考解答

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

解答:

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

public class HashSetTest {
    public static void main(String[] args){

        // 用 HashSet 来存放 String 类型的重复的字符串会发生什么?

        HashSet<String> 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<StringBuilder> 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:96321
s2的hashCode:96321
s3的hashCode:96321
sb1的hashCode:356573597
sb2的hashCode:1735600054
sb3的hashCode:21685669

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

3. 为什么?

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

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

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

参考解答:

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

具体验证思路如果你感兴趣,请查看: 你有没有想过: Java 虚拟机是如何判断两个对象是否相同的?判断的流程是什么?

那为什么相同字符串的不同 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 集合中了。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

数据结构与算法

数据结构与算法

2009-8 / 32.00元

《数据结构与算法》系统地介绍了数据结构的基本概念和基本算法,主要内容包括:绪论,线性表,栈与队列,串,数组、特殊矩阵和广义表,树,图,排序,查找,算法的分析与设计,实验与上机指导。《数据结构与算法》特别注重突出应用性和实践性,实例和习题丰富,并在附录中给出了各章习题的答案。 《数据结构与算法》适合作为应用型本科院校和成人教育计算机专业数据结构课程的教材,也可作为数据结构培训班的教材以及软件从......一起来看看 《数据结构与算法》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具