本文目录导读:

- 方法一:实现
Cloneable接口并重写clone()方法(推荐) - 方法二:使用拷贝构造器(Copy Constructor)
- 方法三:手动字段复制(手动实现)
- 方法四:使用
BeanUtils.cloneBean()(Apache Commons) - 浅拷贝的核心特点
在Java中,浅度拷贝(Shallow Copy)意味着创建一个新对象,然后将原对象的非静态字段的值复制到新对象中,如果字段是基本数据类型,则会复制其值;如果字段是引用类型,则复制的是引用(内存地址),因此新对象和原对象会共享同一个引用类型的子对象。
以下是几种常见的实现浅度拷贝的案例:
实现 Cloneable 接口并重写 clone() 方法(推荐)
这是Java原生支持的浅拷贝方式。
// 1. 定义一个可被浅拷贝的类
class Address implements Cloneable {
String city;
String street;
public Address(String city, String street) {
this.city = city;
this.street = street;
}
@Override
public String toString() {
return "Address{" + "city='" + city + '\'' + ", street='" + street + '\'' + '}';
}
// 为了演示浅拷贝,Address也需要支持clone(但这里我们不深挖)
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
// 2. 实现浅拷贝的主要类
class Person implements Cloneable {
String name;
int age; // 基本类型,直接复制值
Address address; // 引用类型,浅拷贝只复制引用
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
// 重写clone()方法,使用super.clone()实现浅拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
// 关键:调用父类的clone(),默认是浅拷贝
return super.clone();
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + ", address=" + address + '}';
}
}
// 3. 测试浅拷贝
public class ShallowCopyExample {
public static void main(String[] args) throws CloneNotSupportedException {
Address addr = new Address("北京", "长安街");
Person p1 = new Person("张三", 25, addr);
// 浅拷贝
Person p2 = (Person) p1.clone();
System.out.println("=== 浅拷贝后 ===");
System.out.println("p1 = " + p1);
System.out.println("p2 = " + p2);
// 修改p2的基本类型字段 → 不影响p1
p2.name = "李四";
p2.age = 30;
System.out.println("\n=== 修改p2的基本类型属性后 ===");
System.out.println("p1 = " + p1);
System.out.println("p2 = " + p2);
// 修改p2的引用类型字段(Address对象的内容) → 会影响p1(因为共享同一个Address实例)
p2.address.city = "上海";
System.out.println("\n=== 修改p2的引用类型属性后 ===");
System.out.println("p1 = " + p1);
System.out.println("p2 = " + p2);
// 验证p1和p2的address是否指向同一个对象
System.out.println("\np1.address == p2.address ? " + (p1.address == p2.address)); // true
}
}
输出结果:
=== 浅拷贝后 ===
p1 = Person{name='张三', age=25, address=Address{city='北京', street='长安街'}}
p2 = Person{name='张三', age=25, address=Address{city='北京', street='长安街'}}
=== 修改p2的基本类型属性后 ===
p1 = Person{name='张三', age=25, address=Address{city='北京', street='长安街'}}
p2 = Person{name='李四', age=30, address=Address{city='北京', street='长安街'}}
=== 修改p2的引用类型属性后 ===
p1 = Person{name='张三', age=25, address=Address{city='上海', street='长安街'}}
p2 = Person{name='李四', age=30, address=Address{city='上海', street='长安街'}}
p1.address == p2.address ? true
修改 p2.address.city 会影响 p1.address.city,因为两个对象的 address 字段指向同一个 Address 实例,这就是浅拷贝的特征。
使用拷贝构造器(Copy Constructor)
虽然不直接使用 Object.clone(),但这是另一种常见且更安全的浅拷贝实现方式。
class Person {
String name;
int age;
Address address;
// 常规构造器
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
// 拷贝构造器(实现浅拷贝)
public Person(Person other) {
this.name = other.name;
this.age = other.age;
// 直接复制引用,指向同一个Address对象
this.address = other.address;
}
}
// 使用方式
Person p2 = new Person(p1);
手动字段复制(手动实现)
class Person {
String name;
int age;
Address address;
public Person shallowCopy() {
Person copy = new Person();
copy.name = this.name;
copy.age = this.age;
copy.address = this.address; // 直接赋值引用
return copy;
}
}
使用 BeanUtils.cloneBean()(Apache Commons)
需要引入 commons-beanutils 包,默认也是浅拷贝:
import org.apache.commons.beanutils.BeanUtils; Person p2 = (Person) BeanUtils.cloneBean(p1);
浅拷贝的核心特点
| 字段类型 | 浅拷贝行为 |
|---|---|
| 基本类型(int, long 等) | 复制值,修改拷贝对象不影响原对象 |
| 引用类型(对象、数组) | 复制引用,指向同一个对象,修改一个会影响另一个(共享) |
浅拷贝适合场景:
- 对象只有基本类型字段,没有引用类型字段。
- 或者你确认需要让新对象和原对象共享某些内部对象(例如只读缓存、不可变对象)。