encounter2017

encounter2017

V2EX 第 409290 号会员,加入于 2019-05-06 11:39:40 +08:00
encounter2017 最近回复了
4 天前
回复了 WngShhng 创建的主题 Java 讨论个问题:该不该重写 equal 和 hashcode
@WngShhng 这里说的默认的逻辑指的是啥呢? “不同的对象在内存上分配的地址是不同的” ? 所以 new A equals new A == false 一定成立?没有这种说法吧。。。record 就不是这样的吗?我觉得你的假设站不住脚

@prosgtsr
1. 实际是存在这样的业务场景的,我可以随便给你举两个例子。
a. 序列化/拷贝/深度比较时的“已访问映射”:oldNode -> newNode 的映射表
b. 图遍历(比如 AST 、依赖图、对象引用图)要避免循环:用 Set<Object> 记录“访问过的节点实例”

2. 我觉得你说的理由站不住脚。
4 天前
回复了 WngShhng 创建的主题 Java 讨论个问题:该不该重写 equal 和 hashcode
@WngShhng 我还是没太懂,没有场景干说很难理解,你方便具体举一个这种容易出问题的例子,方便理解下吗
4 天前
回复了 WngShhng 创建的主题 Java 讨论个问题:该不该重写 equal 和 hashcode
> 但我认为的是,因为当把一个对象放进哈希表的时候,我会默认它的 hashcode 方法是默认的,也就是每个对象有唯一的哈希值。如果重写了 hashcode ,那么在使用的过程中如果不知道这个类复写了 hashcode ,那么就容易导致代码问题。

这句话有这么几个误解:
1. “每个对象有唯一的哈希值”,hashcode 只有 2^32 个取值方式
2. “复写了 hashcode ,那么就容易导致代码问题”,只要你不是乱实现,比如 hashCode(anything) = 1, 那不会有啥问题,对于 hashset 的使用场景,冲突了也无所谓(性能会劣化一些),实际会用 equals 兜底


然后重写 equals 必须重写 hashcode, 为啥你可以看下面这个例子就知道了

```java

jshell> import java.util.*;

jshell> class User {
...> int id;
...> User(int id) { this.id = id;}
...>
...> @Override public boolean equals(Object o) {
...> return (o instanceof User u) && this.id == u.id;
...> }
...> // 故意不重写 hashCode() —— 这是错误示范
...> }
| 已创建 类 User


jshell> var set = new HashSet<User>();
set ==> []

jshell> set.add(new User(1));
$5 ==> true


jshell> System.out.println("contains(new User(1)) = " + set.contains(new User(1)));
contains(new User(1)) = false

jshell> System.out.println("equals? " + new User(1).equals(new User(1)));
equals? true
```

然后你如果用过 Record 就知道,调用方不知道是否重写不是风险点,相反它是语言/库的常态用法。

```java
import java.util.*;

record User2(int id) {}

var m = Map.of(new User2(1), "ok");
System.out.println(m.get(new User2(1))); // ok
```

然后什么时候重写 equals: 你需要业务上的相等比较而不是内存地址的比较
比如判断 peronaA == personB, Person(age: Int, name: String)
其实就是比较 person.age 和 person.name 这两个字段

这种情况下重写 equals 必须重写 hashcode ,原因上面说了

简单总结下:
1. 默认 hashCode 不保证唯一(取值空间有限、也可能碰撞)
2. 重写 hashCode 本身不是风险点,风险来自 equals/hashCode 契约被破坏
3. 重写 equals 必须重写 hashCode ,否则 HashSet/HashMap 会出现“看起来相等但查不到”的现象

然后还有一个点:
作为 HashMap/HashSet 的 key 时,参与 equals/hashCode 的字段最好不可变;否则对象放进集合后字段变化,会导致后续 get/contains 失败。

而这些功能和可能踩坑的点 JVM 的 Record ( 2020 年首次 preview ) 都帮你实现了 。作为对比:
Kotiln 1.0 版本在 2016 年作为 data class 的核心关键词支持
而这个功能是 Scala 1.0 早在 2004 年 1.0 发布时就作为 case class 支持了
ff 吗,听说裁了挺多
感觉 idea 已经逐渐 eclispe 化了
@katwalk 举个例子来说,常见的误区,通过对话来问:“你是什么模型”,了解过原理就会知道这是不靠谱的,因为这个不是事实,而是根据语料&系统提示词回答的。再比如楼上有人说去问 ai 自己怎么运作的,这又是一个典型得不到答案的错误提问方式,具体原因不难想
@katwalk 原理还是有用的,你知道 token, 知道词表,那你就可以通过手动替换词表做一些很 hack 的事情,可以为中文定制一个更高效的子词词表,让相同的内容用更少的 Token 表示
25 天前
回复了 powersee 创建的主题 程序员 自定义 tree-sitter 的 grammar 真难
有没有合适的用例呢?
38 天前
回复了 JavaGo 创建的主题 程序员 写一个最近做 AI 的感受
《人月神话》:复杂性不会消失,只会转移。AI 没有消除本质复杂性,而是将其从编码环节部分转移到了设计、验证和集成环节,通过 ai 你可以让车子跑的比原来快 10 倍,但车子出问题的频率也会同样增加。
38 天前
回复了 JavaGo 创建的主题 程序员 写一个最近做 AI 的感受
感觉在重新发明编译器和程序员
关于   ·   帮助文档   ·   自助推广系统   ·   博客   ·   API   ·   FAQ   ·   Solana   ·   2543 人在线   最高记录 6679   ·     Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 · 12ms · UTC 15:19 · PVG 23:19 · LAX 07:19 · JFK 10:19
♥ Do have faith in what you're doing.