欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

HashSet如何保证元素不重复(面试必问)

程序员文章站 2022-03-07 19:45:07
目录1.hashset 基本用法2.hashset 无序性3.hashset 错误用法3.1 hashset 与基本数据类型3.2 hashset 与自定义对象类型4.hashset 如何保证元素不重...

本文已收录《java常见面试题》系列,git 开源地址:https://gitee.com/mydb/interview

hashset 实现了 set 接口,由哈希表(实际是 hashmap)提供支持。hashset 不保证集合的迭代顺序,但允许插入 null 值。也就是说 hashset 不能保证元素插入顺序和迭代顺序相同。
hashset 具备去重的特性,也就是说它可以将集合中的重复元素自动过滤掉,保证存储在 hashset 中的元素都是唯一的。

1.hashset 基本用法

hashset 基本操作方法有:add(添加)、remove(删除)、contains(判断某个元素是否存在)和 size(集合数量)。这些方法的性能都是固定操作时间,如果哈希函数是将元素分散在桶中的正确位置。
hashset 基本使用如下:

// 创建 hashset 集合
hashset<string> strset = new hashset<>();
// 给 hashset 添加数据
strset.add("java");
strset.add("mysql");
strset.add("redis");
// 循环打印 hashset 中的所有元素
strset.foreach(s -> system.out.println(s));

2.hashset 无序性

hashset 不能保证插入元素的顺序和循环输出元素的顺序一定相同,也就是说 hashset 其实是无序的集合,具体代码示例如下:

hashset<string> mapset = new hashset<>();
mapset.add("深圳");
mapset.add("北京");
mapset.add("西安");
// 循环打印 hashset 中的所有元素
mapset.foreach(m -> system.out.println(m));

以上程序的执行结果如下:

HashSet如何保证元素不重复(面试必问)

从上述代码和执行结果可以看出,hashset 插入的顺序是:深圳 -> 北京 -> 西安,而循环打印的顺序却是:西安 -> 深圳 -> 北京,所以 hashset 是无序的,不能保证插入和迭代的顺序一致。

ps:如果要保证插入顺序和迭代顺序一致,可使用 linkedhashset 来替换 hashset。

3.hashset 错误用法

有人说 hashset 只能保证基础数据类型不重复,却不能保证自定义对象不重复?这样说对吗?
我们通过以下示例来说明此问题。

3.1 hashset 与基本数据类型

使用 hashset 存储基本数据类型,实现代码如下:

hashset<long> longset = new hashset<>();
longset.add(666l);
longset.add(777l);
longset.add(999l);
longset.add(666l);
// 循环打印 hashset 中的所有元素
longset.foreach(l -> system.out.println(l));

以上程序的执行结果如下:

HashSet如何保证元素不重复(面试必问)

从上述结果可以看出,使用 hashset 可以保证基础数据类型不重复。

3.2 hashset 与自定义对象类型

接下来,将自定义对象存储到 hashset 中,实现代码如下:

public class hashsetexample {
    public static void main(string[] args) {
        hashset<person> personset = new hashset<>();
        personset.add(new person("曹操", "123"));
        personset.add(new person("孙权", "123"));
        personset.add(new person("曹操", "123"));
        // 循环打印 hashset 中的所有元素
        personset.foreach(p -> system.out.println(p));
    }
}
@getter
@setter
@tostring
class person {
    private string name;
    private string password;

    public person(string name, string password) {
        this.name = name;
        this.password = password;
    }
}

以上程序的执行结果如下:

HashSet如何保证元素不重复(面试必问)

从上述结果可以看出,自定义对象类型确实没有被去重,那也就是说 hashset 不能实现自定义对象类型的去重咯?
其实并不是,hashset 去重功能是依赖元素的 hashcode 和 equals 方法判断的,通过这两个方法返回的都是 true 那就是相同对象,否则就是不同对象。而前面的 long 类型元素之所以能实现去重,正是因为 long 类型中已经重写了 hashcode 和 equals 方法,具体实现源码如下:

@override
public int hashcode() {
    return long.hashcode(value);
}
public boolean equals(object obj) {
    if (obj instanceof long) {
        return value == ((long)obj).longvalue();
    }
    return false;
}
//省略其他源码......