Skip to content

Object 类核心作用

Object 是所有类的祖先

在 Java 里,每一个类都直接或间接继承自 Object。没有显式声明父类的类,默认就是 Object 的子类。

java
// 这两种写法等价
class Person { }

class Person extends Object { }

Object 定义了所有对象都应该具备的基本能力——它就像 Java 世界的基本法。

Object 的核心方法

java
public class Object {
    // 对象标识
    public final Class<?> getClass();     // 获取运行时类
    public native int hashCode();         // 哈希码
    protected native Object clone();       // 克隆对象

    // 相等性
    public boolean equals(Object obj);    // 判断相等
    protected void finalize();            // 垃圾回收回调(已废弃)

    // 字符串表示
    public String toString();            // 对象的字符串表示

    // 线程通信
    public final void wait();            // 等待
    public final void notify();          // 唤醒一个
    public final void notifyAll();       // 唤醒全部
}

equals:判断对象相等

equals 默认用 == 比较地址——两个引用是否指向同一个对象。

但对于「值相等」的需求(比如两个名字相同的人被认为是同一个人),需要重写:

java
class Person {
    private String name;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;           // 地址相等必然相等
        if (o == null || getClass() != o.getClass()) return false; // 类型检查
        Person other = (Person) o;
        return Objects.equals(name, other.name); // 属性比较
    }
}

equals 契约(五条规则)

规则含义
自反性x.equals(x) 必须返回 true
对称性x.equals(y)y.equals(x) 结果相同
传递性x.equals(y) && y.equals(z)x.equals(z)
一致性多次调用结果一致
非空性x.equals(null) 返回 false

hashCode:对象的哈希码

hashCode 返回一个整数,用于哈希表(HashMap、HashSet)的快速查找。

核心约定

如果 equals 返回 true,两个对象的 hashCode 必须相同。

java
// 违反了约定——equals 相等但 hashCode 不同
class Broken {
    private int value;

    @Override
    public boolean equals(Object o) {
        return this.value == ((Broken) o).value;
    }

    @Override
    public int hashCode() {
        return new Random().nextInt(); // 每次都不同!违反约定!
    }
}

正确的 hashCode

java
class Person {
    private String name;
    private int age;

    @Override
    public int hashCode() {
        return Objects.hash(name, age); // 简洁
        // 或者手动实现
        // int result = name != null ? name.hashCode() : 0;
        // result = 31 * result + age;
        // return result;
    }
}

为什么用 31?它是个奇数且不太大,乘法和位移能高效计算,同时哈希分布比较均匀。

toString:对象的字符串表示

默认实现返回「类名@哈希码的十六进制」:

java
Person p = new Person("张三", 25);
System.out.println(p); // Person@15db9742 —— 这是什么鬼?

重写后:

java
class Person {
    private String name;
    private int age;

    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

System.out.println(p); // Person{name='张三', age=25} —— 清晰多了

getClass:获取运行时类型

java
Object obj = new Person("张三", 25);

Class<?> clazz = obj.getClass();
System.out.println(clazz.getName());    // com.example.Person
System.out.println(clazz.getSimpleName()); // Person

注意:getClass() 不能被重写,它返回的是实际的运行时类型

clone:对象克隆

clone 创建对象的副本,但需要实现 Cloneable 接口:

java
class Address implements Cloneable {
    private String city;

    @Override
    protected Address clone() throws CloneNotSupportedException {
        return (Address) super.clone(); // 浅拷贝
    }
}

Address original = new Address("北京");
Address copy = original.clone(); // copy 是新的对象,但 city 引用相同

深拷贝需要手动复制引用类型字段。

wait / notify:线程通信

这三个方法是 Java 线程间通信的基础,必须在 synchronized 块中使用:

java
synchronized (lock) {
    while (!condition) {
        lock.wait(); // 等待,释放锁
    }
    // 做事情...
    lock.notify();  // 通知一个等待线程
    // 或者 lock.notifyAll(); 通知所有
}

典型应用:生产者-消费者问题。

finalize:已被废弃

finalize() 在对象被 GC 前调用,但 JDK 9 正式废弃它。

原因是:调用时间不确定、影响 GC 性能、可能造成资源泄漏。

不要使用 finalize,用 try-with-resourcesAutoCloseable 替代。

总结

Object 的方法分三类:

类别方法说明
标识getClass()不能重写,返回运行时类型
相等性equals(), hashCode()通常需要一起重写
字符串toString()推荐重写,便于调试
克隆clone()需要 Cloneable,性能差
线程wait(), notify(), notifyAll()线程间通信
废弃finalize()不要使用

基于 VitePress 构建