原文来自于:zha-ge.cn/java/43

Java Set 不会重复?原来它有“记仇”的本事!

前几天和同事聊天,忽然有人问: “为啥 Java 里的 Set,往里加东西,就是死活不让你重复?它心里到底咋想的?” 我一听,哈,这话题熟,讲起来比吐槽同事还顺!

Set 里的“记仇大法”

你想啊,Set,中文翻译就是“集合”,但它跟“名单”可不一样。名单——随便写谁,重复也没人管。可 Java 的 Set,这可是一份“只能出现一次”的黑名单。你要是往里面塞重复的,Set 就跟个记仇精似的,死活认准你已经来过了。

为啥?其实本质上,Set 不是靠人品,靠的是底层的 hashCodeequals

  • 每次你往 Set 里丢个对象,它悄悄问自己俩问题:
    1. 这东西的 hashCode 跟别人一样吗?
    2. 如果 hashCode 一样,我还能用 equals 抖搂出真实身份吗?

只要发现“老熟人”,它就直接甩锅说,喂,别进来了,等下一个吧。

代码片段来一眼

说到这儿,上点干货,给你看关键步骤:

if (!set.contains(obj)) {
    set.add(obj);
}

嗯,JDK 底层其实比这个还复杂,但道理就是这么个意思。每加一个,都要“打卡登记”——否则,不让进。

踩坑瞬间

这东西好用归好用,我当年刚入职那会儿,却栽了个大跟头。

当时写了个 User 类,里面有 name 和 age,往 HashSet 里丢了一堆“看起来一模一样”的 user:

User user1 = new User("小明", 11);
User user2 = new User("小明", 11);
set.add(user1);
set.add(user2);

我以为二选一,Set 肯定只留一个。结果一打印,两个都在!啊??怎么回事,这不是背叛了“不能重复”的信仰吗!

真相永远藏在 equals/hashCode

后来查了下,这才明白—— 原来自己写的 User 根本没覆写 equals 和 hashCode 啊!人家 Set 判断重复靠的就是这俩,你不写,它就只会比较引用(地址),user1 != user2,当然不当回事。

于是我灰溜溜补上:

@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    User user = (User) o;
    return age == user.age && Objects.equals(name, user.name);
}
// hashCode 也得覆盖!

这下,加多少“同款用户”,Set 都只留一个了!

经验启示

别看 Set 冷酷,无情,其实它就是死认“你有没有本事自证身份”。用 Set 装自定义对象,千!万!记!得!

  • equals/hashCode 必须重写
  • List/数组要“包容”,Set 要“守门”
  • 如果用的是 HashSet,hashCode 绝对是主要判断,TreeSet 则是 compareTo

我们程序员写类,有点像给对象办身份证。身份证号一换(equals/hashCode),Set 才认你。 要不然你每次都“离家出走换新衣服”,它根本不认识你是谁!

以后见了 Set,可别只会往里塞,要让“黑名单”起作用,你得懂规则,否则老是掉进这个“重复元素不生效”的坑。

有啥用呢?去重嘛,统计嘛,社交App判好友……反正场景一大片!

行吧,今天就聊到这儿,这 Set 的“记仇大法”你可别再忘咯。哪天朋友问起,你也能一顿唠嗑吹回去嘿。

—— 代码就像生活,想不重复,可不容易 ?

本站提供的所有下载资源均来自互联网,仅提供学习交流使用,版权归原作者所有。如需商业使用,请联系原作者获得授权。 如您发现有涉嫌侵权的内容,请联系我们 邮箱:[email protected]