MST

星途 面试题库

面试题:Java深拷贝中clone方法在多层嵌套对象结构下的应用及优化

给定一个复杂的Java对象结构,例如`A`类包含`B`类对象,`B`类又包含`C`类对象等多层嵌套,且这些类都实现了`Cloneable`接口。请实现`A`类的深拷贝,并考虑如何优化性能,避免不必要的重复拷贝。同时阐述可能遇到的问题及解决方案。
36.5万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

1. 实现A类的深拷贝

假设类结构如下:

class C implements Cloneable {
    private int value;

    public C(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    @Override
    protected C clone() throws CloneNotSupportedException {
        return (C) super.clone();
    }
}

class B implements Cloneable {
    private C c;

    public B(C c) {
        this.c = c;
    }

    public C getC() {
        return c;
    }

    @Override
    protected B clone() throws CloneNotSupportedException {
        C clonedC = c.clone();
        B clonedB = (B) super.clone();
        clonedB.c = clonedC;
        return clonedB;
    }
}

class A implements Cloneable {
    private B b;

    public A(B b) {
        this.b = b;
    }

    public B getB() {
        return b;
    }

    @Override
    protected A clone() throws CloneNotSupportedException {
        B clonedB = b.clone();
        A clonedA = (A) super.clone();
        clonedA.b = clonedB;
        return clonedA;
    }
}

在上述代码中,A类包含B类对象,B类包含C类对象。每个类都实现了Cloneable接口并重写了clone方法。在A类的clone方法中,先克隆B对象,再克隆A对象本身,并将克隆的B对象赋值给克隆的A对象,以此实现深拷贝。

2. 性能优化

  • 缓存已克隆对象:可以使用一个Map来缓存已经克隆过的对象,避免重复克隆。例如:
import java.util.HashMap;
import java.util.Map;

class C implements Cloneable {
    private int value;

    public C(int value) {
        this.value = value;
    }

    public int getValue() {
        return value;
    }

    @Override
    protected C clone(Map<Object, Object> clonedMap) throws CloneNotSupportedException {
        if (clonedMap.containsKey(this)) {
            return (C) clonedMap.get(this);
        }
        C clonedC = (C) super.clone();
        clonedMap.put(this, clonedC);
        return clonedC;
    }
}

class B implements Cloneable {
    private C c;

    public B(C c) {
        this.c = c;
    }

    public C getC() {
        return c;
    }

    @Override
    protected B clone(Map<Object, Object> clonedMap) throws CloneNotSupportedException {
        if (clonedMap.containsKey(this)) {
            return (B) clonedMap.get(this);
        }
        C clonedC = c.clone(clonedMap);
        B clonedB = (B) super.clone();
        clonedB.c = clonedC;
        clonedMap.put(this, clonedB);
        return clonedB;
    }
}

class A implements Cloneable {
    private B b;

    public A(B b) {
        this.b = b;
    }

    public B getB() {
        return b;
    }

    @Override
    protected A clone() throws CloneNotSupportedException {
        Map<Object, Object> clonedMap = new HashMap<>();
        B clonedB = b.clone(clonedMap);
        A clonedA = (A) super.clone();
        clonedA.b = clonedB;
        return clonedA;
    }
}
  • 使用序列化和反序列化:如果对象结构支持序列化,可以使用ObjectOutputStreamObjectInputStream进行深拷贝。这种方法适用于对象结构简单且所有类都实现了Serializable接口的情况。但它的性能开销较大,不适合频繁调用。

3. 可能遇到的问题及解决方案

  • 循环引用问题:如果对象结构中存在循环引用,例如A类包含B类对象,B类又包含A类对象,普通的克隆方法会导致无限递归。解决方案是使用上述提到的缓存已克隆对象的方法,在克隆过程中判断对象是否已被克隆,避免重复克隆。
  • 未实现Cloneable接口:如果某个嵌套类没有实现Cloneable接口,调用clone方法会抛出CloneNotSupportedException。需要确保所有涉及到的类都实现Cloneable接口。
  • 静态成员和不可变对象:静态成员不会被克隆,因为它们属于类级别而非对象级别。对于不可变对象,无需克隆,直接使用原对象即可,因为其内容不可改变,不会影响深拷贝的语义。