Eclipse 开发技巧与 Java Object 类
本篇是 2017 年 Java 学习笔记系列的第十一天。前半段聊聊 Eclipse 这碗”老酒”怎么喝才高效,并附上它与当今主流 IntelliJ IDEA 的快捷键对照;后半段讲透 Java 万类之祖 Object——equals、hashCode、toString 这三个几乎天天见面的方法,默认实现有什么问题、为什么要重写、重写时必须遵守什么契约。
本篇目标
- 了解 Eclipse 的核心高效操作,并能在 IntelliJ IDEA 中找到对应功能
- 理解 Object 作为类层次结构根类的意义
- 掌握 toString、equals、hashCode 的默认行为与重写动机
- 记住 equals 与 hashCode 之间必须共同遵守的契约
- 能手写一个”标准的”学生类
写在前面:这是一篇 Eclipse 时代的笔记
本文写于 2017 年,当时 Eclipse 是国内 Java 课堂的标配 IDE;如今业界主流早已换成 IntelliJ IDEA。工具会变,但”用熟 IDE”的思路不变:内容辅助、快速修复、代码重构、断点调试,这四板斧在哪个 IDE 里都是吃饭的家伙。Eclipse 里有几个概念放到今天依然值得记住:
- 工作空间(Workspace):源代码按”工作空间 → 项目 → 包 → 类”的层级组织,IDEA 里对应 Project 与 Module。
- 红色与黄色波浪线:红线是编译错误,必须处理,否则跑不起来;黄线是警告(如未使用的变量),可以先放一放,但好习惯是尽早清掉。
- 断点调试:在想观察的行号旁打断点,以 Debug 方式启动,程序会停在断点处,之后单步执行(Eclipse 按 F6,IDEA 按 F8)并观察变量窗口的变化。这是排查逻辑错误的基本功,比在代码里到处打印变量高效得多——打印只能看到结果,断点能看到过程。
常用快捷键对照(Windows/Linux 键位,macOS 下 Ctrl 多对应 Cmd):
| 功能 | Eclipse | IntelliJ IDEA |
|---|---|---|
| 内容辅助(代码提示) | Alt + / | Ctrl + Space |
| 快速修复建议 | Ctrl + 1 | Alt + Enter |
| 格式化代码 | Ctrl + Shift + F | Ctrl + Alt + L |
| 优化导包 | Ctrl + Shift + O | 自动导入,或 Alt + Enter |
| 删除当前行 | Ctrl + D | Ctrl + Y |
| 上下移动代码行 | Alt + ↑ / ↓ | Alt + Shift + ↑ / ↓ |
| 全局查找类 | Ctrl + Shift + T | Ctrl + N |
| 跳转查看源码 | F3 或 Ctrl + 点击 | Ctrl + B 或 Ctrl + 点击 |
| 重命名重构 | Alt + Shift + R | Shift + F6 |
| 抽取方法 | Alt + Shift + M | Ctrl + Alt + M |
| 生成构造/getter/setter | Alt + Shift + S | Alt + Insert |
| 单行注释 | Ctrl + / | Ctrl + / |
不必一次全背下来,先把”提示、修复、格式化、调试”四个用熟,剩下的在用中记。
Object:所有类的共同祖先
Java 中每一个类都直接或间接继承自 Object——即使你没写 extends,编译器也会悄悄补上。这样设计的好处是:任何对象都拥有统一的基本行为(转成字符串、比较相等、计算哈希),任何引用都能用 Object 类型的变量接收,这是多态和整个集合框架得以成立的根基。之前讲构造方法时说”子类构造默认调用父类无参构造”,这条调用链向上追,终点就是 Object 的 public Object()。可以把它理解成 Java 世界里的”出生证明”:只要是个对象,就天然带着这套基础能力。
toString:对象的”名片”
默认实现等价于 getClass().getName() + "@" + Integer.toHexString(hashCode()),打印出来是 com.demo.Student@1b6d3586 这样的东西——类名加一串十六进制,对人类几乎没有信息量。为什么建议重写?因为 System.out.println(student) 实际调用的就是 student.toString(),重写之后,日志和调试输出才能直接看到对象的内容:
|
equals 与 ==:到底什么叫”相等”
== 是运算符:比较基本类型时比值,比较引用类型时比的是地址。Object 默认的 equals 内部就是 ==,所以两个分别 new 出来的 Student,哪怕姓名、年龄完全相同,== 和默认 equals 都是 false——它们在堆中是两个对象。但业务上我们通常认为”字段都一样就是同一个人”,所以要重写 equals,改为比较内容。
重写 equals 必须满足五个契约(面试高频):
- 自反性:
x.equals(x)必须为 true; - 对称性:
x.equals(y)与y.equals(x)结果一致; - 传递性:x 等于 y、y 等于 z,则 x 等于 z;
- 一致性:对象没改动时,多次调用结果一致;
- 对 null:
x.equals(null)必须返回 false。
常见错误:把参数写成具体类型 public boolean equals(Student s)。这不是重写而是重载——HashSet 等集合调用的仍是 Object 版本的 equals,你的方法根本不会被执行。务必加上 @Override,让编译器替你检查。
hashCode:与 equals 的生死契约
hashCode 的默认实现按对象地址计算,不同对象一般不同。哈希容器(HashMap、HashSet)的工作方式是先用 hashCode 定位桶,再用 equals 在桶内逐个确认。它也有三条契约:
- 对象不改动时,多次调用 hashCode 结果必须一致;
- equals 为 true 的两个对象,hashCode 必须相等;
- equals 为 false 时 hashCode 不强制不同,但尽量不同能减少哈希冲突。
由此得出黄金法则:重写 equals 就必须同时重写 hashCode,且两个方法要用同一组字段计算。只重写 equals 的后果很隐蔽:两个”相等”的 Student 能同时放进 HashSet;作为 HashMap 的 key 存进去之后再 get,会因为定位到错误的桶而查不到——对象等于”丢”了。反过来只重写 hashCode 不重写 equals 也一样出问题:桶定位对了,桶内确认环节却仍按地址比较,照样找不到。这也是为什么 IDE 生成这两个方法时总是成对出现。
至于 getClass(),它返回对象的运行时类,是反射的入口,这里先知道名字,反射章节再展开。
经典练习:一个标准的学生类
把上面三个方法落实到代码里:
import java.util.Objects; |
三个要点:@Override 不要省;equals 与 hashCode 必须使用同一组字段;Objects.equals 和 Objects.hash 帮你处理了 null,比手写判空稳妥。验证方式:new 两个姓名年龄都相同的 Student,equals 应返回 true;把它们都放进 HashSet,集合里应只剩一个。日常开发中这些方法通常由 IDE 自动生成(对照表里的”生成”快捷键),但要看得懂它生成的每一行在遵守哪条契约。
小结
- IDE 是放大镜不是拐杖:内容辅助、快速修复、重构、调试四板斧,在 Eclipse 和 IDEA 里一通百通。
- Object 是所有类的根,equals、hashCode、toString 是它发给每个对象的”基础行为”。
- 默认 equals 比地址、toString 打印地址,业务开发中一般都要重写成”按内容”。
- 契约红线:equals 相等 ⇒ hashCode 必须相等;两个方法永远一起重写、用同一组字段。

