How do we make a java class immutable if it has a member variable of another user defined class?

259 Views Asked by At

Recently in an interview for Java Developer role, I was asked how do I make Class A immutable if it has a member variable, which is an object of Class B and in a situation where Class B is external to the project and cannot be edited by the programmer moreover class B might even have a member variable of its own which is an object of another user defined class. I gave it a lot of thought and told the interviewer there is no way unless class B has implemented and exposed a method to deep clone itself.

The interviewer though wasn't convinced. Is there really a way to make such a class immutable?

If I can remember correctly this was the situation he explained. He wanted me to make class A immutable, what would have been the best answer?

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

There are 2 best solutions below

1
On

Don't expose B to the world. So do not have a method which return B.

Instead identify the methods in B, which don't mutate B and let A implement these methods by calling the same method in b.

So if B has a method calcSomething() a should have a calcSomething() methocd which just does return b.calcSomething().

1
On

You may use something like this:

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;
    }
}

It that case Class A is 100% immutable.

Update: Also you can use reflection or seralization to get deep copy of class (if class has deep hierarchy), for example using GSON for seralization:

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

or so on