MST

星途 面试题库

面试题:Java深拷贝在复杂对象图中的实现

假设有一个复杂的Java对象图,其中包含相互引用的多个自定义类,类中既有基本数据类型,又有集合类型以及其他对象引用。请设计并实现一种深拷贝的方案,确保所有层次的对象都被正确拷贝,且不会出现循环引用导致的问题。
23.5万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. 使用序列化和反序列化实现深拷贝
    • 首先,确保需要拷贝的类实现Serializable接口。
    • 示例代码如下:
import java.io.*;

class DeepCopyExample {
    public static <T> T deepCopy(T obj) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bos);
        oos.writeObject(obj);
        ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bis);
        return (T) ois.readObject();
    }
}
  • 这种方法的优点是实现简单,能处理复杂对象图和循环引用。缺点是要求所有类实现Serializable接口,并且性能相对较低,因为涉及到字节流的读写。
  1. 手动递归实现深拷贝
    • 以一个简单的对象层次结构为例,假设有A类,A类包含B类的对象和一个List<String>
import java.util.ArrayList;
import java.util.List;

class B {
    private String data;

    public B(String data) {
        this.data = data;
    }

    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }

    // 深拷贝方法
    public B deepCopy() {
        return new B(data);
    }
}

class A {
    private B b;
    private List<String> list;

    public A(B b, List<String> list) {
        this.b = b;
        this.list = list;
    }

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }

    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    // 深拷贝方法
    public A deepCopy() {
        B newB = b.deepCopy();
        List<String> newList = new ArrayList<>();
        newList.addAll(list);
        return new A(newB, newList);
    }
}
  • 手动递归实现深拷贝需要在每个类中编写深拷贝方法,优点是性能相对较好,不需要实现Serializable接口。缺点是实现复杂,需要手动处理每个层次的对象拷贝,并且处理循环引用需要额外的逻辑,例如可以使用一个Map来记录已经拷贝过的对象。例如:
import java.util.HashMap;
import java.util.Map;

class C {
    private D d;
    private Map<Object, Object> visited = new HashMap<>();

    public C(D d) {
        this.d = d;
    }

    public D getD() {
        return d;
    }

    public void setD(D d) {
        this.d = d;
    }

    public C deepCopy() {
        if (visited.containsKey(this)) {
            return (C) visited.get(this);
        }
        D newD = d.deepCopy(visited);
        C newC = new C(newD);
        visited.put(this, newC);
        return newC;
    }
}

class D {
    private String value;

    public D(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public D deepCopy(Map<Object, Object> visited) {
        if (visited.containsKey(this)) {
            return (D) visited.get(this);
        }
        D newD = new D(value);
        visited.put(this, newD);
        return newD;
    }
}

这样通过Map记录已经拷贝过的对象,在拷贝时如果发现对象已经拷贝过则直接返回已拷贝的对象,从而避免循环引用问题。