Java案例如何实现浅度拷贝?

wen java案例 8

本文目录导读:

Java案例如何实现浅度拷贝?

  1. 方法一:实现 Cloneable 接口并重写 clone() 方法(推荐)
  2. 方法二:使用拷贝构造器(Copy Constructor)
  3. 方法三:手动字段复制(手动实现)
  4. 方法四:使用 BeanUtils.cloneBean()(Apache Commons)
  5. 浅拷贝的核心特点

在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 等) 复制值,修改拷贝对象不影响原对象
引用类型(对象、数组) 复制引用,指向同一个对象,修改一个会影响另一个(共享)

浅拷贝适合场景:

  • 对象只有基本类型字段,没有引用类型字段。
  • 或者你确认需要让新对象和原对象共享某些内部对象(例如只读缓存、不可变对象)。

抱歉,评论功能暂时关闭!