Object是所有类的顶层父类,由Java语言规范、编译器自动补extends Object及JVM加载机制三层保障;接口不继承但实现类间接继承;数组是Object子类,基本类型不是;equals与hashCode必须一同重写以保证哈希集合正确性;wait/notify定义在Object上因操作对象监视器;toString、getClass、clone各有典型使用误区。

Java 中 Object 类是所有类的顶层父类,面试官常借它考察你对 Java 基础、设计思想和底层机制的理解。答得好,不光体现语法掌握,更反映你是否真正“懂 Java”。关键不是背方法名,而是讲清“为什么这样设计”“什么场景用”“踩过哪些坑”。
为什么 Object 是所有类的父类?JVM 怎么保证的?
Java 规定:每个类默认继承 Object(哪怕没写 extends)。编译器在生成字节码时会自动补上 extends java.lang.Object;JVM 加载类时也强制要求所有类的直接父类必须是 Object 或其子类。这不是靠源码继承实现的,而是语言规范 + 编译器 + JVM 三层保障的结果。
- 接口不继承
Object,但接口的实现类会间接继承 —— 所以接口变量也能调用toString()等方法 - 数组类型(如
int[])也是Object的子类(JVM 层面),所以能赋值给Object变量、能调用getClass() - 基本类型(
int、boolean)不是对象,不继承Object;它们的包装类(Integer、Boolean)才是
equals() 和 hashCode() 为什么必须一起重写?
这是高频陷阱题。核心逻辑是:如果两个对象逻辑上相等(equals() 返回 true),它们的 hashCode() 必须相同 —— 否则放进 HashMap 或 HashSet 就会出错(找不到、重复存入)。
- 只重写
equals()不重写hashCode():对象可能被散列到不同桶里,导致contains()返回false,即使它明明在集合中 - 只重写
hashCode()不重写equals():两个不同对象哈希值相同,但equals()返回false,会导致HashMap把它们当不同 key 存进去,逻辑混乱 - IDE(如 IntelliJ)生成的重写代码默认就同步处理两者,就是为守住这个契约
wait() / notify() 为什么定义在 Object 上,而不是 Thread?
因为“等待/唤醒”操作的本质是线程对**对象监视器(monitor)** 的协作,不是对线程本身的操作。每个对象都有一个内置锁(monitor),wait() 是让当前线程释放该对象的锁并进入等待队列;notify() 是唤醒等待该对象锁的某个线程。
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
立即学习“Java免费学习笔记(深入)”;
- 如果定义在
Thread类上,就无法表达“等哪个对象”的语义 —— 线程间通信必须关联具体资源(对象) - 必须在
synchronized块或方法内调用,否则抛IllegalMonitorStateException,因为要确保调用者已持有该对象的锁 -
sleep()是Thread的静态方法,只让当前线程暂停,不释放任何锁 —— 和wait()有本质区别
toString()、getClass()、clone() 的典型误区
这几个方法看着简单,但容易答偏。
-
toString():默认返回类名@哈希值(十六进制),毫无业务意义。业务类务必重写,比如返回关键字段组合,方便日志和调试 -
getClass()返回运行时真实类型(含泛型擦除信息),不能被重写(final方法),但可用反射绕过 —— 面试可提一句“它是获取运行时类型最可靠的方式” -
clone():浅拷贝,且Object.clone()是protected,子类需改为public并实现Cloneable接口(仅作标记,不包含方法)。深拷贝得自己递归处理,或用序列化/第三方库
不复杂但容易忽略 —— 把 Object 当成“基础工具箱”,想清楚每个方法背后的设计意图,比死记方法签名更有分量。

















