Java 浅拷贝和深拷贝

723 阅读2分钟

1.浅拷贝

创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址

1.1 浅拷贝的实现

1.1.1 实现Clone接口

Object父类有个clone()的拷贝方法,不过它是protected类型的,我们需要重写它并修改为public类型。除此之外,子类还需要实现Cloneable接口来告诉JVM这个类是可以拷贝的

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/4 3:42 下午
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable, Cloneable {

    private static final long serialVersionUID = -1286423671768591169L;

    private String name;

    private Integer age;

    private Address address;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/4 3:42 下午
 */
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Address implements Serializable , Cloneable {

    private static final long serialVersionUID = -2220826382327087863L;

    private String country;

    private String city;
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

}

测试

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/4 3:44 下午
 */
public class CloneTest2 {
    public static void main(String[] args) throws CloneNotSupportedException {
        User user1 = User.builder()
                .name("张三")
                .age(18)
                .address(Address.builder()
                        .country("中国")
                        .city("上海")
                        .build())
                .build();

        User user2 = (User) user1.clone();

        System.out.println(user1 == user2); // false
        System.out.println(user1.getAddress() == user2.getAddress()); // true
        
    }
}

1.1.2 使用BeanUtils.copyProperties

import org.springframework.beans.BeanUtils;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/4 3:44 下午
 */
public class CloneTest2 {
    public static void main(String[] args) throws CloneNotSupportedException {
        User user1 = User.builder()
                .name("张三")
                .age(18)
                .address(Address.builder()
                        .country("中国")
                        .city("上海")
                        .build())
                .build();
        User user2 = new User();
        BeanUtils.copyProperties(user1, user2);

        System.out.println(user1 == user2); // false
        System.out.println(user1.getAddress() == user2.getAddress()); // true
    }
}

2.深拷贝

创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

2.1 深拷贝的实现方式

2.1.1 使用SerializationUtils.clone

需要依赖commons-lang3

<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-lang3</artifactId>
    <version>3.11</version>
</dependency>

SerializationUtils.clone需要类实现Serializable接口

import org.apache.commons.lang3.SerializationUtils;

/**
 * Description:
 *
 * @author jack
 * @date 2021/8/4 3:44 下午
 */
public class CloneTest {
    public static void main(String[] args) {
        User user1 = User.builder()
                .name("张三")
                .age(18)
                .address(Address.builder()
                        .country("中国")
                        .city("上海")
                        .build())
                .build();

        User user2 = SerializationUtils.clone(user1);

        System.out.println(user1 == user2); // false
        System.out.println(user1.getAddress() == user2.getAddress()); //false

    }
}