重写tostring()、equals()、hashcode()需严格遵守语义契约:tostring()须防空指针、循环引用、敏感信息泄露及副作用;equals()与hashcode()必须基于完全相同的字段,且hashcode()禁用可变字段;类型检查须用getclass()而非instanceof;空值比较统一用objects.equals()。

重写这三个方法不是“能用就行”,而是有一套隐性但强制的语义契约——违反它不会编译报错,却会让集合、日志、调试在运行时悄悄失灵。
toString() 的隐藏安全线
它可能被日志框架、IDE调试器、JSON序列化工具甚至异常堆栈自动调用,所以必须满足:
- 绝不抛异常:字段为null时不能直接调用
.toString(),要用Objects.toString(field, "null") - 避开循环引用:A包含B、B又引用A时,不能无脑拼接,否则
StackOverflowError - 不暴露敏感信息:密码、token、身份证号等字段必须显式排除,哪怕只是临时调试也不行
- 不触发副作用:禁止在
toString()里查数据库、发HTTP请求、格式化大数组
equals() 和 hashCode() 必须共享同一组字段
不是“差不多就行”,而是逻辑上完全一致:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 如果
equals()比较了id和name,那hashCode()就必须只用这两个字段计算(如Objects.hash(id, name)) - 不能在
equals()里用status判断相等,却在hashCode()里忽略它——这会破坏“相等对象必有相同哈希值”的契约 - 可变字段(如
lastModifiedTime)绝不能参与hashCode(),否则对象加入HashSet后一更新字段,就再也找不到了
类型检查必须用 getClass() != obj.getClass(),不用 instanceof
这是防止继承场景下对称性被破坏的关键细节:
- 若父类
Person重写了equals(),子类Student extends Person也重写,用instanceof Person会导致student.equals(person)为true,但person.equals(student)为false——违反对称性 -
getClass() == obj.getClass()确保只有同类型实例才可能相等,是更严格也更安全的选择
空值与边界处理不能靠手写三元表达式
手动判空既啰嗦又易错,应统一使用工具方法:
- 字段比较一律用
Objects.equals(a, b),自动处理null与非null组合 - 基本类型比较仍用
==,不要包装成Integer再用equals() - 特殊类型如
BigDecimal、LocalDateTime,优先用compareTo()而非equals()(因BigDecimal中1.0和1.00数值相等但equals()返回false)
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










