Java Object 类

张开发
2026/4/16 8:08:40 15 分钟阅读

分享文章

Java Object 类
Java Object 类学习笔记详细版一、Object 类概述java.lang.Object是 Java 类层次结构的根类超类。唯一性Java 中所有的类都直接或间接地继承自Object类。隐式继承如果你定义一个类没有显式继承其他类如class A {}编译器会自动让它继承Object即class A extends Object {}。核心作用它定义了所有对象共有的基本行为如对象标识、字符串表示、哈希码计算、对象克隆、线程同步等。重要提示Object类位于java.lang包中该包会被自动导入因此使用Object类时无需手动import。二、核心方法详解Object类中定义了 11 个方法其中 9 个是public2 个是protected。以下是重点方法的详细解析1.equals(Object obj)作用判断两个对象是否“相等”。默认行为比较两个对象的内存地址即操作符的行为。重写建议对于自定义类通常需要根据对象的内容字段值来判断相等性必须重写此方法。publicclassPerson{privateStringname;privateintage;publicPerson(Stringname,intage){this.namename;this.ageage;}// 重写 equals 方法Overridepublicbooleanequals(Objectobj){// 1. 自反性检查同一个对象if(thisobj)returntrue;// 2. 空值检查if(objnull)returnfalse;// 3. 类型检查if(getClass()!obj.getClass())returnfalse;Personother(Person)obj;// 4. 字段比较 (注意处理 null)if(age!other.age)returnfalse;if(namenull){if(other.name!null)returnfalse;}elseif(!name.equals(other.name))returnfalse;returntrue;}}⚠️ 黄金法则如果重写了equals()必须同时重写hashCode()否则会导致在HashMap、HashSet等集合中无法正常工作。2.hashCode()作用返回对象的哈希码整数用于哈希表如HashMap、HashSet中确定对象的存储位置。默认行为通常基于对象的内存地址计算出一个整数。重写规则在程序运行期间只要对象用于equals比较的字段没有被修改hashCode必须保持一致。如果a.equals(b)为true则a.hashCode()必须等于b.hashCode()。如果a.hashCode() b.hashCode()a.equals(b)不一定为true哈希冲突。OverridepublicinthashCode(){// 使用 Objects 工具类 (Java 7) 或手动计算returnjava.util.Objects.hash(name,age);// 或者手动计算int result name ! null ? name.hashCode() : 0; result 31 * result age; return result;}3.toString()作用返回对象的字符串表示用于调试、日志打印。默认行为返回类名哈希码的十六进制例如com.example.Person15db9742。重写建议通常重写以返回对象的关键字段信息便于阅读。OverridepublicStringtoString(){returnPerson{namename, ageage};}// 使用PersonpnewPerson(张三,25);System.out.println(p);// 输出Person{name张三, age25} (如果重写了)// 输出com.example.Person15db9742 (如果未重写)4.clone()作用创建并返回对象的一个副本浅拷贝。访问修饰符protected。前提条件类必须实现Cloneable接口标记接口无方法否则抛出CloneNotSupportedException。必须重写clone()方法并改为public。浅拷贝 vs 深拷贝浅拷贝复制基本类型字段引用类型字段只复制引用地址原对象和克隆对象共享引用对象。深拷贝递归复制所有引用对象完全独立。classStudentimplementsCloneable{privateStringname;privateintage;publicStudent(Stringname,intage){this.namename;this.ageage;}OverrideprotectedObjectclone()throwsCloneNotSupportedException{returnsuper.clone();// 浅拷贝}}// 使用Students1newStudent(李四,20);Students2(Student)s1.clone();System.out.println(s1s2);// false (地址不同)注意由于clone()机制复杂且容易出错特别是深拷贝现代 Java 开发中更推荐使用复制构造函数或拷贝工厂方法来实现对象复制。5.getClass()作用返回对象运行时的Class对象。用途反射、类型检查。PersonpnewPerson(王五,30);Class?clazzp.getClass();System.out.println(clazz.getName());// 输出com.example.Person6.finalize()作用在对象被垃圾回收器GC回收之前调用。状态已废弃 (Deprecated)(Java 9)。原因执行时间不确定性能差可能导致对象复活不推荐依赖它进行资源清理。替代方案使用try-with-resources、Cleaner或PhantomReference。7.notify(),notifyAll(),wait()作用用于多线程间的线程通信对象监视器。前提必须在synchronized代码块或方法中调用否则抛出IllegalMonitorStateException。wait(): 释放锁让当前线程进入等待状态直到其他线程调用notify()或notifyAll()。notify(): 唤醒一个在此对象监视器上等待的线程。notifyAll(): 唤醒所有在此对象监视器上等待的线程。synchronized(lockObject){while(!condition){lockObject.wait();// 等待}// 执行操作lockObject.notifyAll();// 通知}8.wait(long timeout)/wait(long timeout, int nanos)作用带超时的等待。如果指定时间内未被唤醒线程会自动继续执行。9.hashCode()与equals()的契约面试重点规则说明一致性多次调用hashCode()应返回相同值只要对象用于equals的字段未变。相等性如果a.equals(b)为true则a.hashCode()必须等于b.hashCode()。不等性如果a.hashCode() b.hashCode()a.equals(b)不一定为true哈希冲突允许。非空hashCode()不应为null返回 int天然非空。三、常用工具类java.util.Objects从 Java 7 开始引入了Objects工具类简化了Object方法的调用避免NullPointerException。方法说明Objects.equals(a, b)安全比较处理 null 值。a bObjects.hashCode(o)安全获取哈希码null 返回 0。Objects.requireNonNull(o)如果 o 为 null抛出 NPE否则返回 o。Objects.toString(o)安全转字符串null 返回 “null”。Objects.deepEquals(a, b)深度比较数组内容。示例// 重写 equals 的简化写法Overridepublicbooleanequals(Objectobj){if(thisobj)returntrue;if(objnull||getClass()!obj.getClass())returnfalse;Personperson(Person)obj;returnageperson.ageObjects.equals(name,person.name);// 安全比较}OverridepublicinthashCode(){returnObjects.hash(name,age);// 自动生成哈希码}四、实战场景与最佳实践1. 为什么必须重写equals和hashCode场景将自定义对象放入HashSet或作为HashMap的 Key。后果如果不重写默认比较内存地址。即使两个对象内容完全一样也被视为不同元素导致HashSet中出现重复元素。HashMap中无法通过新对象 Key 获取到旧 Value。2. 如何正确生成equals和hashCodeIDE 生成IntelliJ IDEA 或 Eclipse 中右键 - Generate -equals()andhashCode()。Lombok使用Data或EqualsAndHashCode注解自动生成。手动编写遵循上述规则使用Objects工具类。3. 不可变类Immutable Class如果类是不可变的如String、Integer其hashCode可以缓存提高性能。publicfinalclassImmutablePerson{privatefinalStringname;privatefinalintage;privateinthashCode0;// 缓存// 构造函数...OverridepublicinthashCode(){if(hashCode0){hashCodeObjects.hash(name,age);}returnhashCode;}}4. 深拷贝的实现如果对象包含引用类型字段clone()是浅拷贝。实现深拷贝需要手动递归克隆引用对象。OverrideprotectedObjectclone()throwsCloneNotSupportedException{// 浅拷贝Studentcloned(Student)super.clone();// 深拷贝引用字段 (假设 Address 也实现了 Cloneable)if(this.address!null){cloned.address(Address)this.address.clone();}returncloned;}五、常见面试题Q1:和equals()的区别基本类型比较值。引用类型比较内存地址是否同一个对象。equals()默认Object比较内存地址同。重写后如 String, Person比较对象内容。Q2: 为什么 String 重写了equals和hashCode因为 String 经常作为HashMap的 Key 或HashSet的元素。我们需要根据字符串的内容来判断是否相等而不是内存地址。String 的hashCode被缓存因为 String 是不可变的哈希值不会变性能极高。Q3: 如果只重写equals不重写hashCode会发生什么违反 Java 规范。在HashMap中两个逻辑相等的对象hashCode不同会被放入不同的桶Bucket。结果map.put(key1, val)后map.get(key2)key1.equals(key2) 为 true返回null。Q4:clone()和new的区别new调用构造函数从头创建新对象。clone()在内存中复制现有对象的二进制位不调用构造函数除非在 clone 方法内部显式调用。clone()通常比new快对于复杂对象但实现复杂且易错。Q5:wait()和sleep()的区别特性wait()sleep()所属类ObjectThread锁释放释放锁不释放锁唤醒方式notify()/notifyAll()或超时时间到或被interrupt()使用范围必须在synchronized中任意位置六、总结Object类是 Java 的基石理解它的方法对于掌握 Java 核心至关重要equalshashCode集合框架正常工作的基础必须成对重写。toString调试和日志的关键建议重写。clone了解原理但现代开发慎用推荐复制构造函数。wait/notify多线程通信的核心机制。getClass反射和类型判断的基础。最佳实践始终使用 IDE 或 Lombok 生成equals、hashCode、toString。使用Objects工具类简化代码。理解final、static与这些方法的关系如final类不能被继承static方法不能被重写。掌握Object类是成为 Java 高级开发者的必经之路。

更多文章