原文来自于:zha-ge.cn/java/43
Java Set 不会重复?原来它有"记仇"的本事!
前几天和同事聊天,忽然有人问: "为啥 Java 里的 Set,往里加东西,就是死活不让你重复?它心里到底咋想的?" 我一听,哈,这话题熟,讲起来比吐槽同事还顺!
Set 里的"记仇大法"
你想啊,Set,中文翻译就是"集合",但它跟"名单"可不一样。名单------随便写谁,重复也没人管。可 Java 的 Set,这可是一份"只能出现一次"的黑名单。你要是往里面塞重复的,Set 就跟个记仇精似的,死活认准你已经来过了。
为啥?其实本质上,Set 不是靠人品,靠的是底层的 hashCode 和 equals。
- 每次你往 Set 里丢个对象,它悄悄问自己俩问题:
- 这东西的 hashCode 跟别人一样吗?
- 如果 hashCode 一样,我还能用 equals 抖搂出真实身份吗?
只要发现"老熟人",它就直接甩锅说,喂,别进来了,等下一个吧。
代码片段来一眼
说到这儿,上点干货,给你看关键步骤:
java
if (!set.contains(obj)) {
set.add(obj);
}
嗯,JDK 底层其实比这个还复杂,但道理就是这么个意思。每加一个,都要"打卡登记"------否则,不让进。
踩坑瞬间
这东西好用归好用,我当年刚入职那会儿,却栽了个大跟头。
当时写了个 User 类,里面有 name 和 age,往 HashSet 里丢了一堆"看起来一模一样"的 user:
java
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,当然不当回事。
于是我灰溜溜补上:
java
@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 的"记仇大法"你可别再忘咯。哪天朋友问起,你也能一顿唠嗑吹回去嘿。
------ 代码就像生活,想不重复,可不容易 😊