当前位置: 首页 > news >正文

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 个是public,2 个是protected。以下是重点方法的详细解析:

1.equals(Object obj)

作用:判断两个对象是否“相等”。
默认行为:比较两个对象的内存地址(即==操作符的行为)。
重写建议:对于自定义类,通常需要根据对象的内容(字段值)来判断相等性,必须重写此方法。

publicclassPerson{privateStringname;privateintage;publicPerson(Stringname,intage){this.name=name;this.age=age;}// 重写 equals 方法@Overridepublicbooleanequals(Objectobj){// 1. 自反性检查:同一个对象if(this==obj)returntrue;// 2. 空值检查if(obj==null)returnfalse;// 3. 类型检查if(getClass()!=obj.getClass())returnfalse;Personother=(Person)obj;// 4. 字段比较 (注意处理 null)if(age!=other.age)returnfalse;if(name==null){if(other.name!=null)returnfalse;}elseif(!name.equals(other.name))returnfalse;returntrue;}}

⚠️ 黄金法则:如果重写了equals()必须同时重写hashCode(),否则会导致在HashMapHashSet等集合中无法正常工作。


2.hashCode()

作用:返回对象的哈希码(整数),用于哈希表(如HashMapHashSet)中确定对象的存储位置。
默认行为:通常基于对象的内存地址计算出一个整数。
重写规则

  1. 在程序运行期间,只要对象用于equals比较的字段没有被修改,hashCode必须保持一致。
  2. 如果a.equals(b)true,则a.hashCode()必须等于b.hashCode()
  3. 如果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.Person@15db9742)。
重写建议:通常重写以返回对象的关键字段信息,便于阅读。

@OverridepublicStringtoString(){return"Person{name='"+name+"', age="+age+"}";}// 使用Personp=newPerson("张三",25);System.out.println(p);// 输出:Person{name='张三', age=25} (如果重写了)// 输出:com.example.Person@15db9742 (如果未重写)

4.clone()

作用:创建并返回对象的一个副本(浅拷贝)。
访问修饰符protected
前提条件

  1. 类必须实现Cloneable接口(标记接口,无方法),否则抛出CloneNotSupportedException
  2. 必须重写clone()方法并改为public

浅拷贝 vs 深拷贝

  • 浅拷贝:复制基本类型字段,引用类型字段只复制引用地址(原对象和克隆对象共享引用对象)。
  • 深拷贝:递归复制所有引用对象,完全独立。
classStudentimplementsCloneable{privateStringname;privateintage;publicStudent(Stringname,intage){this.name=name;this.age=age;}@OverrideprotectedObjectclone()throwsCloneNotSupportedException{returnsuper.clone();// 浅拷贝}}// 使用Students1=newStudent("李四",20);Students2=(Student)s1.clone();System.out.println(s1==s2);// false (地址不同)

注意:由于clone()机制复杂且容易出错(特别是深拷贝),现代 Java 开发中更推荐使用复制构造函数拷贝工厂方法来实现对象复制。


5.getClass()

作用:返回对象运行时的Class对象。
用途:反射、类型检查。

Personp=newPerson("王五",30);Class<?>clazz=p.getClass();System.out.println(clazz.getName());// 输出:com.example.Person

6.finalize()

作用:在对象被垃圾回收器(GC)回收之前调用。
状态已废弃 (Deprecated)(Java 9+)。
原因:执行时间不确定,性能差,可能导致对象复活,不推荐依赖它进行资源清理。
替代方案:使用try-with-resourcesCleanerPhantomReference


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 == b
Objects.hashCode(o)安全获取哈希码,null 返回 0。
Objects.requireNonNull(o)如果 o 为 null,抛出 NPE;否则返回 o。
Objects.toString(o)安全转字符串,null 返回 “null”。
Objects.deepEquals(a, b)深度比较数组内容。

示例

// 重写 equals 的简化写法@Overridepublicbooleanequals(Objectobj){if(this==obj)returntrue;if(obj==null||getClass()!=obj.getClass())returnfalse;Personperson=(Person)obj;returnage==person.age&&Objects.equals(name,person.name);// 安全比较}@OverridepublicinthashCode(){returnObjects.hash(name,age);// 自动生成哈希码}

四、实战场景与最佳实践

1. 为什么必须重写equalshashCode

场景:将自定义对象放入HashSet或作为HashMap的 Key。
后果:如果不重写,默认比较内存地址。即使两个对象内容完全一样,也被视为不同元素,导致:

  • HashSet中出现重复元素。
  • HashMap中无法通过新对象 Key 获取到旧 Value。

2. 如何正确生成equalshashCode

  • IDE 生成:IntelliJ IDEA 或 Eclipse 中,右键 -> Generate ->equals()andhashCode()
  • Lombok:使用@Data@EqualsAndHashCode注解自动生成。
  • 手动编写:遵循上述规则,使用Objects工具类。

3. 不可变类(Immutable Class)

如果类是不可变的(如StringInteger),其hashCode可以缓存,提高性能。

publicfinalclassImmutablePerson{privatefinalStringname;privatefinalintage;privateinthashCode=0;// 缓存// 构造函数...@OverridepublicinthashCode(){if(hashCode==0){hashCode=Objects.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 重写了equalshashCode

  • 因为 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 核心至关重要:

  1. equals&hashCode:集合框架正常工作的基础,必须成对重写。
  2. toString:调试和日志的关键,建议重写。
  3. clone:了解原理,但现代开发慎用,推荐复制构造函数。
  4. wait/notify:多线程通信的核心机制。
  5. getClass:反射和类型判断的基础。

最佳实践

  • 始终使用 IDE 或 Lombok 生成equalshashCodetoString
  • 使用Objects工具类简化代码。
  • 理解finalstatic与这些方法的关系(如final类不能被继承,static方法不能被重写)。

掌握Object类,是成为 Java 高级开发者的必经之路。

http://www.jsqmd.com/news/604470/

相关文章:

  • TMC5160步进电机驱动芯片
  • ESP8266实战指南:用PWM调光控制LED亮度
  • 嘎嘎降AI vs 快降鸭 vs 文必过:3款平价降AI工具谁更值?
  • 从零到一:ESP32-S3构建端侧语音AI助手的全链路实践
  • 自动化测试框架知识
  • 基于A星算法的路径规划平滑优化算法(拐点的圆弧化处理)A星算法+路径优化Matlab实现
  • 杨氏矩阵找第N大(小)的O(N)线性算法 LeetCode 378. Kth Smallest Element in a Sorted Matrix 373. Find K Pairs 钓鱼问题
  • 2026年3月泡棉制造商推荐:行业口碑评价深度分析,有实力的泡棉赋能企业生产效率提升与成本优化 - 品牌推荐师
  • mmap 文件映射 [系统加餐]
  • 工业质检实战:用Dinomaly+Anomalib搞定多品类缺陷检测(附完整配置流程)
  • 【技术底稿 09】MySQL 主从搭建完不算完!37 岁老码农生产级三件套:巡检 + 双节点监控 + 异地备份
  • Web-Maker布局系统完全指南:如何选择最适合你项目的界面布局
  • 微调BERT进行命名实体识别
  • 技术决策的民主与集中:软件测试团队如何寻求平衡?
  • 前端复古风选型必看!像素UI 、精简复古风UI
  • 基于Transformer-BiGRU 5模型多变量时序预测一键对比 (多输入单输出)附Matlab代码
  • NeRF在游戏开发中的5个神级应用:从场景重建到角色动画
  • Java NIO Files 类
  • 2026实测|6款主流PPT生成软件横评,打工人再也不用熬到深夜做PPT - 品牌测评鉴赏家
  • WithClock 桌面时钟,极致轻量化,鼠标穿透无打扰,自定义皮肤,双模式时钟,打造沉浸式桌面时间体验
  • Swagger中常用注解
  • 基于FPGA XDMA中断与双缓存架构的PCIE 3.0性能实测与优化
  • python sendgrid
  • 2026年AI PPT工具大揭秘,轻松解锁高效创作 - 品牌测评鉴赏家
  • 视频批量裁剪助手 - 支持 AVI、MKV 等多格式批量处理,精准设置裁剪时间
  • 【企业级MCP微服务基座】:基于FastAPI+Pydantic+Structured Logging的Python模板,已通过金融级压测(QPS 12,800+)
  • 滑模控制、反步控制、传统PID四旋翼无人机轨迹跟踪控制仿真
  • Taskwarrior钩子脚本开发终极指南:如何扩展你的任务管理功能
  • 如何用抖音下载器实现内容创作效率提升300%?一个开源工具的全方位指南
  • 硬字幕去除难题终结者:AI驱动的Video-subtitle-remover如何重新定义视频修复