必须同时重写equals()和hashcode(),因为若a.equals(b)为true,则a.hashcode()必须等于b.hashcode();否则hashmap等集合无法正确定位或去重。

直接聚焦三个最常考、最容易出错的核心方法:equals、hashCode 和 toString。掌握它们的逻辑关系和重写规范,比死记所有11个方法更高效、更实用。
equals 和 hashCode 必须一起重写
默认的 equals 只比较内存地址,hashCode 返回基于地址的整数——这导致两个内容相同的对象在 HashMap 里被当成不同键,存不进同一个桶,也查不出来。
- 只要重写了 equals,就必须重写 hashCode,否则集合类行为异常
- 核心契约:如果 a.equals(b) 返回 true,那么 a.hashCode() == b.hashCode() 必须成立
- 不要用可变字段(比如后期会被 set 修改的属性)参与 hashCode 计算,否则对象放进 HashSet 后改字段,就再也找不到了
- 用 IDE 自动生成(如 IntelliJ 的 Alt+Insert → “equals and hashCode”)最稳妥,它会自动处理 null、类型检查和字段选择
toString 是调试时的第一张脸
默认输出是 Person@1b6d3586 这种无意义字符串,日志和断点里根本看不出状态。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 重写目标不是炫技,而是清晰表达关键字段,例如 "User{id=101, name='Alice', age=28}"
- 避免在 toString 里调用耗时操作(如数据库查询、远程接口)、加锁或触发复杂计算——它可能被日志框架、JMX 或 IDE 在任意线程中调用
- 用 Lombok 的 @ToString 或 Objects.toStringHelper(Guava)能大幅减少模板代码
getClass 不能重写,但要懂它干啥用
它是 final 方法,返回运行时真正的 Class 对象,不受多态干扰。面试常问“为什么不用 instanceof 判断类型”,答案就在这里。
- getClass() == obj.getClass() 比 instanceof 更严格:能区分父类和子类实例(比如 Parent 和 Child 都继承自同一父类,但不认为相等)
- 反射场景下必须用 getClass() 获取真实类型,才能安全调用 getDeclaredMethod 或 setAccessible
- 在 equals 实现里,通常用 getClass() 做类型校验,而不是 instanceof,防止违反对称性
wait/notify 不是 sleep,要用对地方
它们不是让线程暂停几秒的工具,而是配合 synchronized 实现线程间条件等待的底层机制。
- 必须在 synchronized 方法或同步块里调用,否则抛 IllegalMonitorStateException
- wait() 会释放锁并挂起当前线程;notify() 唤醒一个等待线程(不指定哪个),notifyAll() 唤醒全部
- 永远用 while 循环包裹 wait(),而不是 if——因为存在虚假唤醒(spurious wakeup)
- 典型场景:生产者-消费者、线程池任务队列、阻塞式 IO 封装
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










