Java Object clone() 方法(保姆级教程)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
对象复制:程序设计中的“复印机”
在程序开发中,对象复制是一个常见需求。想象你正在整理一份重要文档,想要快速生成一份一模一样的副本:此时,Java 的 Object clone()
方法就像一台智能复印机,能帮你快速创建对象的复制品。但与普通复印机不同,这个“复印”过程需要开发者掌握一定的规则和技巧。接下来,我们将从基础概念到实际案例,逐步揭开 Object clone()
方法的奥秘。
浅拷贝与深拷贝:对象复制的两种形态
浅拷贝(Shallow Copy)
浅拷贝是指创建一个新对象,并将原对象的所有字段复制到新对象中。但若字段是引用类型(如对象或数组),新对象与原对象将共享同一个引用。这就像复印一份文件夹:新文件夹里装的仍是原文件夹的“指针”,而非文件内容本身。
代码示例:
class Student {
String name;
int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
}
public class Main {
public static void main(String[] args) {
Student original = new Student("Alice", 20);
// 假设 clone() 方法实现了浅拷贝
Student copy = original.clone();
copy.name = "Bob";
System.out.println(original.name); // 输出 Alice
}
}
关键点:
- 基本类型(如
int
)的值会被独立复制 - 引用类型(如
String
)的地址会被复制,导致新旧对象共享同一对象
深拷贝(Deep Copy)
深拷贝则会递归复制所有引用类型字段,确保新对象与原对象完全独立。这相当于将文件夹中的所有文件内容都重新生成,而非共享原文件。
代码示例:
class Address {
String city;
}
class Employee {
String name;
Address address;
public Employee(String name, Address address) {
this.name = name;
this.address = address;
}
}
public class Main {
public static void main(String[] args) {
Address originalAddress = new Address("New York");
Employee original = new Employee("John", originalAddress);
// 假设 clone() 方法实现了深拷贝
Employee deepCopy = original.clone();
deepCopy.address.city = "Los Angeles";
System.out.println(original.address.city); // 输出 New York
}
}
关键点:
- 深拷贝会递归复制所有嵌套对象,确保修改新对象不影响原对象
- 实现深拷贝需要额外处理引用类型的复制逻辑
Object.clone() 方法的实现机制
基础步骤与规则
Object.clone()
方法是 Java 提供的浅拷贝实现,其使用需遵循以下规则:
- 实现
Cloneable
接口:若未实现该接口,调用clone()
会抛出CloneNotSupportedException
- 重写
clone()
方法:需在子类中覆盖clone()
方法,调用super.clone()
获取父类字段的拷贝
代码示例:
public class Person implements Cloneable {
String name;
int age;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 调用 Object 类的 clone() 方法
}
}
常见问题与解决方案
问题 1:未实现 Cloneable 接口的异常
若直接调用 clone()
而未实现 Cloneable
接口,程序会抛出异常。这类似于使用复印机时未放入纸张,设备会发出警报。
解决方案:
// 正确实现方式
public class Product implements Cloneable {
double price;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
问题 2:如何实现深拷贝?
Object.clone()
默认为浅拷贝,若需深拷贝,可采取以下两种方式:
- 手动递归复制:在
clone()
方法中显式复制所有引用字段
class Car implements Cloneable {
String model;
Engine engine;
@Override
protected Object clone() throws CloneNotSupportedException {
Car clonedCar = (Car) super.clone();
clonedCar.engine = (Engine) engine.clone(); // 手动深拷贝发动机对象
return clonedCar;
}
}
- 序列化方案:利用
Serializable
接口实现深拷贝
public static <T extends Serializable> T deepClone(T object) {
try {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (T) ois.readObject();
} catch (Exception e) {
throw new RuntimeException("深拷贝失败", e);
}
}
实战案例:克隆复杂对象结构
案例 1:学生信息的浅拷贝与深拷贝
class Course {
String name;
}
class Student implements Cloneable {
String id;
Course course;
@Override
protected Object clone() throws CloneNotSupportedException {
Student clonedStudent = (Student) super.clone();
// 实现深拷贝需复制 Course 对象
clonedStudent.course = new Course();
clonedStudent.course.name = this.course.name;
return clonedStudent;
}
}
案例 2:订单系统的克隆需求
class OrderItem {
String productId;
int quantity;
}
class Order implements Cloneable {
String orderId;
List<OrderItem> items;
@Override
protected Object clone() throws CloneNotSupportedException {
Order clonedOrder = (Order) super.clone();
// 深拷贝 items 列表
clonedOrder.items = new ArrayList<>();
for (OrderItem item : this.items) {
OrderItem clonedItem = new OrderItem();
clonedItem.productId = item.productId;
clonedItem.quantity = item.quantity;
clonedOrder.items.add(clonedItem);
}
return clonedOrder;
}
}
总结:合理使用 clone() 方法的要点
-
明确需求:
- 浅拷贝适合简单对象或仅需独立基础字段的场景
- 复杂对象需通过深拷贝避免意外引用共享
-
遵循规则:
- 总要实现
Cloneable
接口,避免异常 - 在
clone()
方法中通过super.clone()
调用父类逻辑
- 总要实现
-
性能权衡:
- 手动深拷贝需逐层复制,适合结构固定的对象
- 序列化深拷贝通用但可能消耗更多资源
通过理解 Java Object clone()
方法的底层逻辑与实现细节,开发者可以像使用复印机一样高效安全地复制对象。无论是处理业务实体还是算法数据结构,合理选择浅拷贝或深拷贝策略,将为代码的健壮性和可维护性提供有力保障。