Java Object 類別

Object 是 Java 中所有類別的根類別,每個類別都直接或間接繼承自 Object,因此所有物件都有 Object 定義的方法。

主要方法

public class Object {
    public String toString();
    public boolean equals(Object obj);
    public int hashCode();
    public final Class<?> getClass();
    protected Object clone() throws CloneNotSupportedException;
    public final void wait() throws InterruptedException;
    public final void notify();
    public final void notifyAll();
    protected void finalize() throws Throwable;  // 已棄用
}

toString()

預設回傳類別名稱和雜湊碼:

public class Person {
    private String name;
    private int age;
    
    // 建議覆寫 toString
    @Override
    public String toString() {
        return "Person{name='" + name + "', age=" + age + "}";
    }
}

Person p = new Person("Alice", 25);
System.out.println(p);  // Person{name='Alice', age=25}

equals() 和 hashCode()

預設行為

Object obj1 = new Object();
Object obj2 = new Object();

obj1.equals(obj2);  // false(比較參考)
obj1 == obj2;       // false
obj1.hashCode();    // 記憶體位址衍生的數值

覆寫 equals()

public class Person {
    private String name;
    private int age;
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && Objects.equals(name, person.name);
    }
    
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

equals 和 hashCode 契約

  1. 相等的物件必須有相同的 hashCode
  2. hashCode 相同的物件不一定相等
  3. 覆寫 equals 就必須覆寫 hashCode

getClass()

Person p = new Person();
Class<?> clazz = p.getClass();

System.out.println(clazz.getName());        // com.example.Person
System.out.println(clazz.getSimpleName());  // Person

// 類型比較
if (p.getClass() == Person.class) {
    System.out.println("是 Person 類型");
}

clone()

public class Person implements Cloneable {
    private String name;
    private int age;
    
    @Override
    protected Person clone() throws CloneNotSupportedException {
        return (Person) super.clone();  // 淺複製
    }
}

Person original = new Person("Alice", 25);
Person copy = original.clone();

深複製

public class Person implements Cloneable {
    private String name;
    private Address address;
    
    @Override
    protected Person clone() throws CloneNotSupportedException {
        Person cloned = (Person) super.clone();
        cloned.address = this.address.clone();  // 複製參考物件
        return cloned;
    }
}

執行緒相關方法

Object lock = new Object();

// wait/notify 必須在 synchronized 區塊內使用
synchronized (lock) {
    lock.wait();     // 等待
    lock.notify();   // 喚醒一個等待的執行緒
    lock.notifyAll(); // 喚醒所有等待的執行緒
}

Objects 工具類別

import java.util.Objects;

// 空值安全的比較
Objects.equals(a, b);

// 產生 hashCode
Objects.hash(field1, field2, field3);

// 空值檢查
Objects.requireNonNull(obj, "不能為 null");

// 空值安全的 toString
Objects.toString(obj, "預設值");

// 判斷是否為 null
Objects.isNull(obj);
Objects.nonNull(obj);

Record 自動實作

Java 16+ 的 Record 自動實作 equals、hashCode、toString:

public record Person(String name, int age) {}

Person p1 = new Person("Alice", 25);
Person p2 = new Person("Alice", 25);

p1.equals(p2);    // true
p1.hashCode();    // 自動生成
p1.toString();    // Person[name=Alice, age=25]

重點整理

  • 所有類別都繼承自 Object
  • 覆寫 toString() 提供有意義的字串表示
  • 覆寫 equals() 必須同時覆寫 hashCode()
  • getClass() 取得物件的類別資訊
  • clone() 需要實作 Cloneable 介面
  • 使用 Objects 工具類別簡化操作
  • Record 類型自動實作這些方法