杰瑞科技汇

Java Object类有哪些核心方法?

Object 类是 Java 所有类的父类,无论是直接继承还是间接继承,所有的 Java 类都拥有 Object 类中定义的方法,理解这些方法是掌握 Java 面向对象编程的基础。

Object 类位于 java.lang 包中,它是一个 final 类,不能被继承。

下面我将这些方法分为几类进行详细说明,并附上代码示例。

Object 类的核心方法总览

方法签名 方法分类 描述
public final native Class<?> getClass() 对象信息 返回此 Object 的运行时类。
public int hashCode() 对象信息 返回该对象的哈希码值。
public boolean equals(Object obj) 对象比较 指示其他某个对象是否与此对象“相等”。
protected native Object clone() throws CloneNotSupportedException 对象创建 创建并返回此对象的一个副本。
public String toString() 对象信息 返回该对象的字符串表示。
public final native void notify() 线程通信 唤醒在此对象监视器上等待的单个线程。
public final native void notifyAll() 线程通信 唤醒在此对象监视器上等待的所有线程。
public final native void wait() throws InterruptedException 线程通信 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法。
public final native void wait(long timeout) throws InterruptedException 线程通信 导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法,或者超过指定的时间量。
protected void finalize() throws Throwable 垃圾回收 当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。(已废弃)

详细解析与示例

getClass()

  • 作用: 返回一个 Class 对象,该对象表示对象的运行时类,这个 Class 对象包含了类的完整信息,如类名、父类、接口、方法、字段等。
  • 特点:
    • final 方法,不能被重写。
    • native 方法,由 JVM 实现,效率高。
  • 示例:
    String str = "Hello, World!";
    Class<?> clazz = str.getClass();
    System.out.println(clazz.getName()); // 输出: java.lang.String
    System.out.println(clazz.getSimpleName()); // 输出: String

hashCode()

  • 作用: 返回一个整数值,作为该对象的“哈希码”,哈希码的主要作用是在哈希表(如 HashMap, HashSet)中确定对象的存储位置。

  • 特点:

    • 约定:
      1. 在 Java 应用程序执行期间,如果用于 equals 比较的信息没有被修改,那么同一个对象多次调用 hashCode() 方法必须返回相同的整数。
      2. 如果两个对象根据 equals(Object) 方法是相等的,那么这两个对象的 hashCode() 方法必须返回相同的整数。
      3. 如果两个对象根据 equals(Object) 方法是不相等的,那么这两个对象的 hashCode() 方法不必须返回不同的整数(但这样做可以提高哈希表的性能)。
    • 默认实现: Object 类的 hashCode() 方法返回一个基于对象内存地址的哈希码,因此即使两个内容完全相同但内存地址不同的对象,其默认的 hashCode() 也不同。
  • 示例:

    Person p1 = new Person("Alice", 30);
    Person p2 = new Person("Alice", 30);
    System.out.println(p1.hashCode()); // 输出一个基于内存地址的哈希码
    System.out.println(p2.hashCode()); // 输出另一个基于内存地址的哈希码
    // 在下面自定义 equals 和 hashCode 后,p1 和 p2 的哈希码将相同

equals(Object obj)

  • 作用: 比较两个对象是否“相等”。

  • 特点:

    • 默认实现: Object 类的 equals 方法内部使用 比较两个对象的内存地址,只有当两个引用指向同一个对象时,才返回 true
    • 重写约定: 我们会重写 equals 方法来比较对象的“内容”是否相等,重写 equals 时,必须同时重写 hashCode 方法,以遵守上述的约定。
  • 示例:

    // 默认的 equals 比较
    String s1 = new String("hello");
    String s2 = new String("hello");
    System.out.println(s1.equals(s2)); // 输出 true,因为 String 类重写了 equals
    Person p1 = new Person("Alice", 30);
    Person p2 = new Person("Alice", 30);
    System.out.println(p1.equals(p2)); // 输出 false,因为 Person 类未重写 equals
    // 自定义 Person 类并重写 equals 和 hashCode
    class Person {
        private String name;
        private int age;
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            Person person = (Person) o;
            return age == person.age && Objects.equals(name, person.name);
        }
        @Override
        public int hashCode() {
            return Objects.hash(name, age);
        }
    }
    Person p3 = new Person("Alice", 30);
    Person p4 = new Person("Alice", 30);
    System.out.println(p3.equals(p4)); // 输出 true

toString()

  • 作用: 返回一个字符串表示,用于描述对象,这个字符串通常包含类的名字和有用的信息,方便调试和日志打印。

  • 特点:

    • 默认实现: 返回一个格式为 getClass().getName() + '@' + Integer.toHexString(hashCode()) 的字符串。com.example.Person@15db9742
    • 重写约定: 几乎所有情况下,我们都会重写 toString() 方法,使其返回一个更有意义的、可读的字符串。
  • 示例:

    class Person {
        private String name;
        private int age;
        // ... 构造函数 ...
        @Override
        public String toString() {
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    Person p = new Person("Bob", 25);
    System.out.println(p); // 隐式调用 p.toString()
    // 输出: Person{name='Bob', age=25}

clone()

  • 作用: 创建并返回一个对象的新副本,即“浅拷贝”。

  • 特点:

    • native 方法,性能高。
    • 受保护: clone() 方法是 protected 的,因此外部不能直接调用一个对象的 clone() 方法,只有实现了 Cloneable 接口的类才能调用 Objectclone() 方法。
    • 浅拷贝: 默认的 clone() 方法会复制对象的所有字段,对于基本数据类型,会复制其值;对于引用数据类型,只会复制引用地址,而不是引用指向的对象,原始对象和克隆对象的引用类型字段会指向同一个对象。
    • 需要实现接口: 要使用 clone(),类必须实现 java.lang.Cloneable 接口(这是一个标记接口,没有方法),否则会抛出 CloneNotSupportedException
  • 示例:

    class Address {
        String city;
        public Address(String city) { this.city = city; }
    }
    class Employee implements Cloneable {
        String name;
        Address address;
        public Employee(String name, Address address) {
            this.name = name;
            this.address = address;
        }
        // 重写 clone 方法
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone(); // 调用 Object 的 clone() 方法,执行浅拷贝
        }
        @Override
        public String toString() {
            return "Employee{name='" + name + "', address=" + address.city + "}";
        }
    }
    public class Main {
        public static void main(String[] args) throws CloneNotSupportedException {
            Address addr = new Address("New York");
            Employee original = new Employee("John", addr);
            Employee cloned = (Employee) original.clone();
            System.out.println("Original: " + original);
            System.out.println("Cloned:   " + cloned);
            // 修改克隆对象的 address
            cloned.address.city = "Boston";
            System.out.println("\nAfter modifying cloned's address:");
            System.out.println("Original: " + original); // 输出 Original: Employee{name='John', address=Boston}
            System.out.println("Cloned:   " + cloned);   // 输出 Cloned:   Employee{name='John', address=Boston}
            // 原始对象的地址也被修改了,证明了浅拷贝的特性
        }
    }

    注意: clone() 方法由于存在一些问题(如接口设计不佳、浅拷贝的陷阱),通常不推荐使用,更推荐使用拷贝构造函数或序列化/反序列化的方式来创建对象的深拷贝。

notify(), notifyAll(), wait()

  • 作用: 这三个方法是 Java 多线程编程中的核心,用于线程间的通信和同步。
  • 特点:
    • 它们必须在同步代码块同步方法中调用,否则会抛出 IllegalMonitorStateException
    • 调用这些方法的当前线程必须拥有该对象的监视器锁。
    • wait(): 使当前线程等待,直到其他线程调用此对象的 notify()notifyAll() 方法。wait() 会释放锁。
    • notify(): 随机唤醒一个在此对象监视器上等待的线程。
    • notifyAll(): 唤醒所有在此对象监视器上等待的线程,它们会竞争获取锁。
  • 示例: 这三个方法通常配合 synchronized 关键字一起使用,是生产者-消费者模型等经典场景的基础。

finalize()

  • 作用: 垃圾回收器在回收一个对象之前,会调用该对象的 finalize() 方法。
  • 特点:
    • 已废弃: 从 Java 9 开始,finalize() 方法被标记为 deprecated(废弃),不推荐在新代码中使用。
    • 不可靠: JVM 不保证 finalize() 一定会被调用,例如程序正常退出时。
    • 性能问题: finalize() 的执行时机不确定,且会严重影响垃圾回收的性能。
    • 替代方案: 如果需要执行清理操作(如关闭文件、网络连接),应该使用 try-finally 块或 try-with-resources 语句。

方法 是否必须重写 关键点
getClass() final, native, 用于获取运行时类型信息。
hashCode() 当重写 equals() 时必须重写 保证 equals 相等的对象 hashCode 必须相等。
equals(Object) 当需要自定义“相等”逻辑时重写 默认比较内存地址,重写后应比较内容。
toString() 强烈建议重写 默认输出无意义信息,重写后用于调试和日志。
clone() 通常不推荐使用 实现复杂,易出错(浅拷贝陷阱),推荐其他拷贝方式。
notify(), notifyAll(), wait() 多线程同步通信的基础,必须在同步代码块中调用。
finalize() 已废弃,不应使用 不可靠,影响性能,使用 try-finallytry-with-resources 替代。

掌握 Object 类的方法是理解 Java 面向对象机制和高级特性的基石。equalshashCode 的正确使用,以及 toString 的重写,是日常开发中最频繁、最重要的实践。

分享:
扫描分享到社交APP
上一篇
下一篇