1

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;
    }
}
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724

2 Answers2

2

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().

MTilsted
  • 5,425
  • 9
  • 44
  • 76
  • This would have been my answer, BUT it's not 100%, the questioner was correct that it's not really possible. The un-owned class in an un-owned package could refer to an un-owned static variable that could be mutated externally. I suppose you could take it one further and copy the state of the external class into local member variables--then you'd have a good immutable state but could not access method code from the potentially mutable class. – Bill K Nov 30 '15 at 18:46
0

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

Slava Vedenin
  • 58,326
  • 13
  • 40
  • 59
  • Actually class C came into picture when I gave him the reply that I will not provide a getter to B and instead in class A itself write delegates to methods of B that don't expose its state. The depth of member variable of user defined classes can be anything just for explaining its 3 here. C might have D and so on. – Saurav Shekhar Nov 30 '15 at 19:04