Java Object 类笔记

在 Java 的世界里,Object类是一切类的始祖。理解它的核心方法,掌握String及其相关类的特性,是每一个 Java 开发者从入门到精通的必经之路。本文将系统地梳理 Object 类的 11 个核心方法,深入探讨equalshashCode的约定,并全面对比StringStringBufferStringBuilder的区别。

一、Object 类有哪些核心方法?

JavaObject类是所有类的超类,默认提供 11 个核心方法,涵盖了对象比较、哈希、字符串表示、线程同步等方面。

1.equals(Object obj)

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

  • 说明:默认实现比较内存地址(与==相同)。实际开发中通常需要重写,按对象的内容(如字段值)判断相等性。

2.hashCode()

  • 作用:返回对象的哈希码值。

  • 说明:与equals配套使用。若两个对象equals返回true,则hashCode必须相等;若hashCode不等,则equals必为false。如果只重写equals不重写hashCode,会导致对象在HashMapHashSet等集合中无法正确存储。

3.toString()

  • 作用:返回对象的字符串表示。

  • 说明:默认格式为“类名 + @ + 对象的十六进制哈希码”(如User@1b6d3586),可读性差。通常重写为返回对象的具体信息,便于日志打印和调试。

4.getClass()

  • 作用:返回对象运行时的实际类对象。

  • 说明final方法,不可重写。常用于反射,获取类的名称、方法、字段等信息,也可用于运行时类型检查。

5.clone()

  • 作用:创建并返回对象的一个副本。

  • 说明:用于对象的浅拷贝。使用clone需要实现Cloneable接口,否则抛出CloneNotSupportedException

6.notify()

  • 作用:随机唤醒一个等待当前对象锁的线程。

  • 说明:必须在同步块中使用。

7.notifyAll()

  • 作用:唤醒所有等待当前对象锁的线程。

  • 说明:必须在同步块中使用。

8.wait()

  • 作用:让当前线程释放对象锁并进入等待状态,直到被notify/notifyAll唤醒。

  • 说明:必须在同步块中调用,通常放在循环中检查等待条件以避免“虚假唤醒”。

9.wait(long timeout)

  • 作用:让当前线程等待指定的毫秒数,超时后自动唤醒。

  • 说明timeout为 0 表示无限等待。

10.wait(long timeout, int nanos)

  • 作用:提供更精确的时间控制(毫秒 + 纳秒)。

  • 说明:实际超时时间可能受系统调度影响。

11.finalize()

  • 作用:垃圾回收器回收对象前调用,用于执行清理工作。

  • 说明已过时(Deprecated since Java 9)。执行时机不确定,可能影响性能,甚至导致对象复活。替代方案是使用try-with-resourcesPhantomReference

二、== 与 equals 有什么区别?

  • ==:对于基本数据类型,比较的是值是否相同;对于引用数据类型,比较的是引用地址是否相同。

  • equals():不能用于基本数据类型。Object类中的equals()默认使用==比较地址。但String类重写了equals()方法,先比较地址,地址不同则比较内容是否相同。

三、为什么重写 equals 方法时必须重写 hashCode 方法?

在 Java 中,equalshashCode遵循以下约定:

  • 一致性:如果obj1.equals(obj2)返回true,那么obj1.hashCode()必须等于obj2.hashCode()

  • 非一致性:如果两个对象的hashCode相同,equals不一定为true(哈希冲突)。

如果不重写hashCode,可能导致对象在哈希集合(如HashMapHashSet)中无法正确存储。例如,两个id相同的User对象,equals返回true,但hashCode不同,会被当成两个不同元素存入集合。

四、Java 中 String 的常用方法有哪些?

  • int length():返回字符串长度。

  • boolean equals(Object obj):比较字符串内容是否相同(区分大小写)。

  • String substring(int beginIndex):从指定索引开始截取子串。

  • String trim():去除字符串首尾空白字符。

  • String replace(char oldChar, char newChar):替换所有指定字符。

  • boolean isEmpty():判断字符串长度是否为 0(注意:null调用会报错)。

五、String、StringBuffer、StringBuilder 的区别与联系

1. 可变性

  • String:不可变(Immutable),每次修改都会生成新对象。

  • StringBuilder / StringBuffer:可变(Mutable),可直接修改内容。

2. 线程安全性

  • String:天然线程安全。

  • StringBuilder:非线程安全,适合单线程。

  • StringBuffer:线程安全(方法使用synchronized),适合多线程。

3. 性能

  • String:性能最低,频繁修改会产生大量临时对象。

  • StringBuilder:性能最高,无同步开销。

  • StringBuffer:性能略低于StringBuilder,因有同步开销。

4. 使用场景

  • String:字符串内容固定或变化少。

  • StringBuilder:单线程下频繁修改字符串。

  • StringBuffer:多线程下频繁修改字符串。

特性StringStringBufferStringBuilder
不可变性不可变可变可变
线程安全
性能
适用场景少量修改多线程单线程

六、String 为什么是不可变的?

因为String底层使用final修饰的char[]数组存储字符。数组本身不可变,且String类没有提供修改数组内容的方法,所有“修改”操作都会返回新对象。

Java Object 类深度解析

这种设计带来了线程安全、字符串常量池复用、哈希值缓存等好处。

总结

  • Object类是 Java 的根类,掌握其核心方法是理解 Java 面向对象的基础。

  • equalshashCode的约定是哈希集合正确工作的关键。

  • StringStringBuilderStringBuffer的选择直接影响程序性能和线程安全性。