V2EX encounter2017
encounter2017

encounter2017

V2EX 第 409290 号会员,加入于 2019-05-06 11:39:40 +08:00
encounter2017 最近回复了
3 天前
回复了 v2306 创建的主题 程序员 现实版刻舟求剑
你说它刻舟求剑,但是他知道为了避免时间的影响,特意用年份来做变量,因为这个不太容易变,真出了 bug 用户重试一遍就好了,摸不着头脑以为是偶然。他真的我哭死
@WngShhng 这里说的默认的逻辑指的是啥呢? “不同的对象在内存上分配的地址是不同的” ? 所以 new A equals new A == false 一定成立?没有这种说法吧。。。record 就不是这样的吗?我觉得你的假设站不住脚

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

2. 我觉得你说的理由站不住脚。
@WngShhng 我还是没太懂,没有场景干说很难理解,你方便具体举一个这种容易出问题的例子,方便理解下吗
> 但我认为的是,因为当把一个对象放进哈希表的时候,我会默认它的 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 表示
39 天前
回复了 powersee 创建的主题 程序员 自定义 tree-sitter 的 grammar 真难
有没有合适的用例呢?
52 天前
回复了 JavaGo 创建的主题 程序员 写一个最近做 AI 的感受
《人月神话》:复杂性不会消失,只会转移。AI 没有消除本质复杂性,而是将其从编码环节部分转移到了设计、验证和集成环节,通过 ai 你可以让车子跑的比原来快 10 倍,但车子出问题的频率也会同样增加。
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2775 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 12ms UTC 06:16 PVG 14:16 LAX 22:16 JFK 01:16
Do have faith in what you're doing.
ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86