如果java类具有另一个用户定义类的成员变量,我们如何使它成为不可变的?

时间:2015-11-30 18:36:12

标签: java immutability deep-copy defensive-copy

最近在接受Java Developer角色的采访时,我被问到如果它有一个成员变量,我是如何使A类不可变的,这是一个B类的对象,并且在一个B类在项目外部但不能的情况下由程序员编辑,而且B类甚至可能有自己的成员变量,这是另一个用户定义的类的对象。我给了它很多想法并且告诉面试官除非B级已经实施并且暴露了一种深度克隆自身的方法,否则没有办法。

面试官虽然不相信。有没有办法让这样的类不可变?

如果我能记得正确,那就是他解释的情况。他希望我让A级成为不可变的,那会是最好的答案吗?

final public class A {
    final private B b;

    A(B b) {
        this.b = b; // Class b might/might not be cloneable
        // this.b = (B)b.clone();
    }

    public B getB() {
        return b;
        // return (B)b.clone();
    }
}

class B // external cannot edit
{
    C c;

    public C getC() {
        return c;
    }

    public void setC(C c) {
        this.c = c;
    }
}

class C // external cannot edit
{
    int i;
    String j;

    public int getI() {
        return i;
    }

    public void setI(int i) {
        this.i = i;
    }

    public String getJ() {
        return j;
    }

    public void setJ(String j) {
        this.j = j;
    }
}

2 个答案:

答案 0 :(得分:2)

不要向世界揭露B.所以没有一个返回B的方法。

而是识别B中的方法,它不会改变B并让A通过调用b中的相同方法来实现这些方法。

因此,如果B有方法calcSomething(),则应该有一个calcSomething()方法,它只返回b.calcSomething()。

答案 1 :(得分:0)

您可以使用以下内容:

final public class A {
    final private B b;

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

    public B getB() {
        return cloneB(b);
    }

    private static B cloneB(b){ 
        B newB = new B(); 
        C c = new C();
        c.setI(b.getC().getI());
        c.setJ(b.getC().getJ());
        newB.setC(c); 
        return newB;
    }
}

A类是100%不可变的情况。

更新:您还可以使用反射或分区来获取类的深层副本(如果类具有深层次结构),例如使用GSON进行分类:

private static B cloneB(b){ 
    String tmp = new GSON().toJson(b);
    return new GSON().fromJson(tmp, B.class);
}

左右