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

tClass()、hashCode()、clone()、notify()、notifyAll()、wait(long timeout ...

Java Object 类核心方法实战解析:tClass()、hashCode()、clone()、notify()、notifyAll()、wait()

在 Java 中,Object类是所有类的根父类,它定义了若干关键方法,这些方法在多线程、对象比较、克隆等场景中有着至关重要的应用。本文将从实战角度出发,深入解析tClass()hashCode()clone()notify()notifyAll()wait(long timeout)这几个方法,并通过代码示例演示它们的用法和注意事项。## 1. getClass() —— 运行时类型识别getClass()方法返回当前对象的运行时类(Class对象),常用于反射和类型判断。注意,它返回的是实际运行时的类型,而不是编译时声明的类型。### 代码示例:getClass() 实战java// 文件:GetClassDemo.javapublic class GetClassDemo { public static void main(String[] args) { Object obj = new String("Hello"); // 运行时类型是 String,而不是 Object System.out.println("运行时类型:" + obj.getClass()); // class java.lang.String // 通过 Class 对象获取类名 String className = obj.getClass().getName(); System.out.println("类名:" + className); // java.lang.String // 使用反射创建对象(实际项目中谨慎使用) try { Class<?> clazz = Class.forName("java.lang.StringBuilder"); Object sb = clazz.newInstance(); // 已过时,但演示概念 System.out.println("反射创建的对象类型:" + sb.getClass()); } catch (Exception e) { e.printStackTrace(); } }}输出结果:运行时类型:class java.lang.String类名:java.lang.String反射创建的对象类型:class java.lang.StringBuilder实战要点:-getClass()返回的是Class<?>对象,可用于获取方法、字段、注解等元数据。- 不要用obj.getClass() == String.class来判断类型,推荐使用instanceof运算符。## 2. hashCode() —— 哈希码的生成与约定hashCode()返回对象的哈希码(整数),用于支持基于哈希的集合(如HashMapHashSet)。它必须遵循以下约定:- 同一对象多次调用hashCode()应返回相同值(前提是对象未修改影响哈希码的字段)。- 如果equals()返回true,则两个对象的hashCode()必须相等。- 如果equals()返回false,则两个对象的hashCode()可以不相等(但相等会提高哈希表性能)。### 代码示例:正确实现 hashCode() 和 equals()java// 文件:Person.javaimport java.util.Objects;public class Person { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } // 重写 equals():基于 name 和 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); } // 重写 hashCode():与 equals() 保持一致性 @Override public int hashCode() { return Objects.hash(name, age); // 使用 Objects 工具类 } // 测试 main 方法 public static void main(String[] args) { Person p1 = new Person("Alice", 25); Person p2 = new Person("Alice", 25); Person p3 = new Person("Bob", 30); System.out.println("p1.equals(p2): " + p1.equals(p2)); // true System.out.println("p1.hashCode() == p2.hashCode(): " + (p1.hashCode() == p2.hashCode())); // true System.out.println("p1.equals(p3): " + p1.equals(p3)); // false System.out.println("p1.hashCode() == p3.hashCode(): " + (p1.hashCode() == p3.hashCode())); // false(可能) }}输出结果:p1.equals(p2): truep1.hashCode() == p2.hashCode(): truep1.equals(p3): falsep1.hashCode() == p3.hashCode(): false实战要点:- 如果重写equals(),必须重写hashCode(),否则哈希集合(如HashSet)会失效。- 使用Objects.hash()是生成哈希码的推荐方式,它内部处理了数组和 null 值。## 3. clone() —— 对象的浅拷贝与深拷贝clone()方法用于创建对象的副本。默认实现是浅拷贝(复制基本类型和引用地址),且要求类实现Cloneable接口(否则抛出CloneNotSupportedException)。### 代码示例:浅拷贝 vs 深拷贝java// 文件:CloneDemo.javaclass Address { String city; Address(String city) { this.city = city; } // 为了演示浅拷贝,不重写 clone()}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(); // 浅拷贝 } // 演示深拷贝:需要手动复制引用对象 public Employee deepClone() throws CloneNotSupportedException { Employee cloned = (Employee) super.clone(); // 手动创建新的 Address 对象 cloned.address = new Address(this.address.city); return cloned; } public static void main(String[] args) throws CloneNotSupportedException { Address addr = new Address("Beijing"); Employee e1 = new Employee("Tom", addr); // 浅拷贝 Employee e2 = (Employee) e1.clone(); System.out.println("浅拷贝后修改地址:"); e2.address.city = "Shanghai"; // 修改 e2 的地址 System.out.println("e1.address.city: " + e1.address.city); // Shanghai(被影响了!) System.out.println("e2.address.city: " + e2.address.city); // Shanghai // 深拷贝 Employee e3 = e1.deepClone(); e3.address.city = "Shenzhen"; System.out.println("\n深拷贝后修改地址:"); System.out.println("e1.address.city: " + e1.address.city); // Shanghai(不受影响) System.out.println("e3.address.city: " + e3.address.city); // Shenzhen }}输出结果:浅拷贝后修改地址:e1.address.city: Shanghaie2.address.city: Shanghai深拷贝后修改地址:e1.address.city: Shanghaie3.address.city: Shenzhen实战要点:- 默认clone()是浅拷贝,对于包含可变引用对象的类,务必实现深拷贝。- 推荐使用拷贝构造函数或工厂方法代替clone(),因为clone()设计存在缺陷(如返回类型强制转型、Cloneable接口只是标记)。## 4. wait()、notify()、notifyAll() —— 线程间通信这三个方法用于线程间的等待与通知,必须由持有对象锁的线程调用(即在synchronized块内),否则抛出IllegalMonitorStateException。-wait():让当前线程进入等待状态,并释放锁。-wait(long timeout):等待指定毫秒数后自动唤醒。-notify():随机唤醒一个等待该对象锁的线程。-notifyAll():唤醒所有等待该对象锁的线程。### 代码示例:生产者-消费者模型java// 文件:ProducerConsumerDemo.javaclass Buffer { private int data; private boolean hasData = false; // 消费者方法 public synchronized int consume() throws InterruptedException { while (!hasData) { // 使用 while 循环防止虚假唤醒 System.out.println("消费者等待数据..."); wait(); // 释放锁,等待生产者通知 } hasData = false; System.out.println("消费者消费数据: " + data); notifyAll(); // 通知生产者可以生产 return data; } // 生产者方法 public synchronized void produce(int value) throws InterruptedException { while (hasData) { System.out.println("生产者等待消费者消费..."); wait(); // 等待消费者消费 } data = value; hasData = true; System.out.println("生产者生产数据: " + value); notifyAll(); // 通知消费者可以消费 }}public class ProducerConsumerDemo { public static void main(String[] args) { Buffer buffer = new Buffer(); // 生产者线程 Thread producer = new Thread(() -> { for (int i = 1; i <= 5; i++) { try { buffer.produce(i); Thread.sleep(1000); // 模拟生产耗时 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); // 消费者线程 Thread consumer = new Thread(() -> { for (int i = 1; i <= 5; i++) { try { buffer.consume(); Thread.sleep(500); // 模拟消费耗时 } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } }); producer.start(); consumer.start(); }}输出结果(示例):生产者生产数据: 1消费者等待数据...消费者消费数据: 1消费者等待数据...生产者生产数据: 2消费者消费数据: 2...(交替执行)实战要点:- 总是在while循环中调用wait(),避免因虚假唤醒导致条件不满足时继续执行。- 使用notifyAll()notify()更安全,因为notify()可能唤醒错误的线程导致死锁。-wait(long timeout)在超时后会自动唤醒,适合设置最大等待时间。## 总结本文从实战角度详细解析了Object类的六个核心方法:-getClass():运行时类型识别,用于反射和动态类型判断。-hashCode() 和 equals():必须成对重写,保证哈希集合的正确性。-clone():浅拷 vs 深拷贝,推荐使用工厂方法替代。-wait() / notify() / notifyAll():线程间通信的基石,需在同步块内使用并注意虚假唤醒。掌握这些方法不仅能加深对 Java 对象模型的理解,还能在实际编码中避免常见的陷阱(如哈希冲突、线程死锁)。建议在真实项目中多编写单元测试验证这些行为,确保代码的健壮性。

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

相关文章:

  • C语言%符号全解析:取余运算与格式化输入输出的核心技巧
  • 嵌入式开发学习日志(二维数组、 字符数组、 函数入门) day9 持续更新中
  • 部队管理系统:人员车辆信息化管理系统
  • 手术机器人+生成式AI=新外科范式?斯坦福外科实验室披露:术中实时规划响应速度提升6.3倍,误差<0.17mm
  • 暖通公司做舒适家项目管道选哪个品牌?水系统五大组成部件配套、地面构造分层设计与舒适家交付标准化程度对比 - 小橘甄选
  • D3D8to9终极指南:让经典游戏在现代Windows上焕发新生
  • STM32F103外设全景解析:从GPIO到DMA的嵌入式开发核心
  • 嘉准BGS-E背景抑制光电传感器:过滤背景反光深色吸光干扰
  • FigmaCN中文汉化插件:3分钟让Figma界面说中文,设计师必备效率神器
  • 贵煌.刺梨火腿月饼:三分火腿香,七分刺梨爽,一口解锁贵州味
  • 数据可视化的星际新装:datart新增13款科技边框与11个未来感装饰元素
  • MEA优化BP神经网络在工业故障预测中的应用
  • 多行业差异化投放:不同的行业应该选择哪家软文营销平台?2026GEO获客落地指南
  • 坐标测量技术:用好程序镜像功能,让对称零件编程效率翻倍
  • 电解槽智能监测管理平台方案
  • 【make+google】用日程做高灵活度搞自动化AI个人知识库
  • 数据库中一些常用英文单词含义
  • 大模型技术入门:从原理到应用落地
  • α-β-γ滤波器:从原理到嵌入式C语言实现的卡尔曼滤波简化版
  • 解决Windows远程桌面CredSSP加密Oracle修正错误:从原理到实战修复
  • MATLAB App Designer实战:从脚本到图形化应用的开发指南
  • STM32系统架构与时钟树详解:从总线矩阵到时钟配置实战
  • RFID电子标签定制厂家能力评估,从绑定制程、复合精度到倒封装良率的核心指标拆解 - 小橘甄选
  • 别再混淆备份与归档!海量数据时代,企业数据保护需要双轨并行
  • 2026年短剧出海成本科普:咔咔猩与传统编剧定制模式对比分析
  • 【AI搜索代码问题终极指南】:20年资深架构师亲授5大高频场景的精准定位与秒级修复方案
  • 云端Android集群的终极底座:傲晨云手机如何凭开放架构赢得2026年8月开发者首选
  • USB协议深度解析:从枚举、传输类型到实战开发入门
  • 四一级空气能怎么选?这三点省电关键别忽略
  • 企业微信群机器人 Webhook 高效告警方案与限流应对策略