java 面试 -- 深拷贝与浅拷贝

一、浅拷贝

浅拷贝是指拷贝对象时仅仅拷贝对象本身和对象中的基本数据类型,而不拷贝对象中的引用类型。换句话说,对于对象中的引用类型,浅拷贝只是拷贝了引用,而没有拷贝引用的对象。因此,原对象和拷贝后的对象共享同一个引用对象

下面是一个浅拷贝的示例:

public class ShallowCopyExample {  
    private int value;  
    private String refValue;  
  
    public ShallowCopyExample(int value, String refValue) {  
        this.value = value;  
        this.refValue = refValue;  
    }  
  
    // getter 和 setter 省略  
  
    @Override  
    public String toString() {  
        return "ShallowCopyExample{" +  
                "value=" + value +  
                ", refValue='" + refValue + '\'' +  
                '}';  
    }  
  
    public static void main(String[] args) {  
        ShallowCopyExample original = new ShallowCopyExample(1, "Original");  
        ShallowCopyExample copied = new ShallowCopyExample(original.getValue(), original.getRefValue());  
        System.out.println("Original: " + original);  
        System.out.println("Copied: " + copied);  
        copied.setRefValue("Copied");  
        System.out.println("After modification:");  
        System.out.println("Original: " + original);  
        System.out.println("Copied: " + copied);  
    }  
}

在上面的示例中,我们创建了一个ShallowCopyExample类,它包含一个基本数据类型value和一个引用类型refValue。在main方法中,我们创建了一个原始对象original,并通过浅拷贝创建了一个拷贝对象copied。当我们修改copied对象的refValue属性时,可以发现原始对象original的refValue属性也被修改了,这是因为它们共享同一个引用对象。

二、深拷贝

深拷贝是指拷贝对象时不仅拷贝对象本身和基本数据类型,还递归拷贝对象中的引用类型。也就是说,对于对象中的引用类型,深拷贝会创建一个新的对象,并将原对象中的引用指向新创建的对象。因此,原对象和拷贝后的对象不共享任何引用对象。

在Java中,实现深拷贝通常有两种方法:

1. 使用序列化和反序列化;

通过实现Serializable接口,我们可以将对象转换为字节流,然后再从字节流中恢复出一个新的对象。这个过程会创建对象所有属性的新副本,包括引用类型属性指向的对象。

2. 使用拷贝构造函数和覆写clone方法。

这种方法需要手动编写代码来递归地复制对象的所有属性。需要注意的是,如果对象包含循环引用,这种方法可能会导致无限递归。

对于特定的数据类型,如集合或数组,Java也提供了相关的拷贝方法,如ArrayList的addAll()方法或数组的copyOf()方法。但是这些方法通常只适用于浅拷贝。

三、 深拷贝的工具类

在Java中,实现深拷贝的工具类有很多,包括一些第三方库如Apache Commons Lang和Google Guava,以及Java标准库中的clone()方法和序列化机制。下面是一些常见的深拷贝工具类和方法:

1. Apache Commons Lang的SerializationUtils

Apache Commons Lang库提供了一个名为SerializationUtils的工具类,它可以通过序列化和反序列化来实现对象的深拷贝。使用这种方法的一个优点是它可以处理复杂的对象图,包括循环引用。

import org.apache.commons.lang3.SerializationUtils;  
  
// ...  
  
MyObject original = new MyObject();  
// 设置original对象的属性...  
  
MyObject copied = SerializationUtils.clone(original);

请注意,这种方法要求对象及其所有嵌套对象都实现了Serializable接口。

2. Java的clone()方法和自定义克隆

Java的Object类提供了一个受保护的clone()方法,用于创建并返回此对象的一个拷贝。如果类实现了Cloneable接口,就可以调用此方法。但是,默认的clone()方法实现的是浅拷贝,所以需要在类中覆写此方法来实现深拷贝。

public class MyObject implements Cloneable {  
    private MyNestedObject nestedObject;  
  
    @Override  
    protected Object clone() throws CloneNotSupportedException {  
        MyObject obj = (MyObject) super.clone();  
        obj.nestedObject = (MyNestedObject) this.nestedObject.clone();  
        return obj;  
    }  
  
    // MyNestedObject类也需要实现clone()方法来进行深拷贝...  
}

3. 使用Java序列化进行深拷贝

另一种利用Java序列化实现深拷贝的方法是手动序列化对象到字节流,然后从字节流中反序列化出一个新的对象。这种方法类似于SerializationUtils,但它是手动实现的。

java
import java.io.*;  
  
public class DeepCopyUtil {  
    public static <T> T deepCopy(T object) {  
        try {  
            // 将对象写入到字节流中  
            ByteArrayOutputStream bos = new ByteArrayOutputStream();  
            ObjectOutputStream oos = new ObjectOutputStream(bos);  
            oos.writeObject(object);  
            oos.flush();  
            oos.close();  
  
            // 从字节流中恢复对象  
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());  
            ObjectInputStream ois = new ObjectInputStream(bis);  
            @SuppressWarnings("unchecked")  
            T copy = (T) ois.readObject();  
            ois.close();  
            return copy;  
        } catch (IOException | ClassNotFoundException e) {  
            throw new RuntimeException(e);  
        }  
    }  
}

4. 使用第三方库如Google Guava

Google Guava库也提供了一些用于深拷贝的工具,但它不像Apache Commons Lang那样直接提供一个通用的深拷贝方法。相反,Guava提供了一些实用程序类和方法,可以帮助你更容易地实现深拷贝逻辑。

在选择深拷贝工具类时,需要考虑对象的复杂性、性能需求、是否支持循环引用以及是否需要额外的库依赖等因素。如果对象的结构相对简单,并且没有循环引用,那么自定义的clone()方法可能就足够了。对于更复杂的场景,使用Apache Commons Lang或Java序列化可能是更好的选择。

三、 常见面试汇总

面试题目1:Object类的clone()方法实现的是深拷贝还是浅拷贝?

Object类的clone()方法实现的是浅拷贝。它只会复制对象的非引用类型属性和引用类型属性的引用,而不会复制引用的对象本身。因此,如果对象包含引用类型属性,那么这些属性在拷贝后仍然指向原始对象中的对象。

要实现深拷贝,通常需要在具体的类中覆写clone()方法,并递归地复制所有引用类型属性指向的对象。

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值