h4ck3d
h4ck3d

Reputation: 6364

Is this java class immutable?

I was implementing an immutable class whose structure is as below :

public final class A{
    private final B bOb;
    public A(){
        bOb = new B();
    }
    public A(A a){
        bOb = new B(a.bOb);
    }
    public A addData(Type data){ // Type - Integer,String,char,etc.
        A newA = new A(this); //making a copy of the object that is calling addData method
        newA.bOb.add(data);
        return newA;
    }
}

Is this implementation correct ? Let's say the object bOb is a list.

Upvotes: 3

Views: 244

Answers (5)

EthanB
EthanB

Reputation: 4289

Your implementation:

public A addData(int data){
    A newA = new A(this);
    newA.bOb.add(data); // <--- bOb is mutable
    return newA;
}

A bOb is being changed, so if you expose any direct access to bOb, it can be changed. (Since you're not exposing anything about bOb, the scenario doesn't make sense.)

Hints:

  • Collections.emptyList() returns an immutable list.
  • Collections.unmodifiableList() returns an immutable shallow-copy of a given list.

Consider this "safer" implementation:

import java.util.*;

public final class A<T>{ //T must also be immutable (String, integer, char, ...)
    private final List<T> list;
    public A(){
        this.list = Collections.emptyList();
    }
    public A(List<T> list){
        this.list = Collections.unmodifiableList(list);
    }
    public A<T> addData(T data){
        List<T> shallowCopy = new ArrayList<T>(this.list);
        shallowCopy.add(data);
        return new A<T>(shallowCopy);
    }
    public List<T> getItems() {
        return this.list;
    }
}

Upvotes: 2

davioooh
davioooh

Reputation: 24676

It depends on how B(B b) constructor works. If it is a copy constructor, it should make a deep copy of b fields. In this case A is immutable.

Instead if the constructor simply take the reference to the same b instance, any change to it will reflect on bOb property, so the A class in not immutable...

Upvotes: 0

mikera
mikera

Reputation: 106351

It is not totally immutable, since B appears to be mutable itself (via the add method) and A contains an instance of B.

However I think it is effectively immutable (i.e. it behaves as if it was immutable from the perspective of an external observer) providing that all the following are true:

  • new B(B) performs a complete deep copy of B (if not then addData may mutate something within the original B)
  • you aren't leaking references to bOb via any other means
  • the elements added themselves are immutable

You get most of the benefits of immutability from being effectively immutable so I think this design is OK providing Type is immutable - it's fine to mutate an object during it's construction providing it never gets mutated after you pass a reference to someone else. A good example of this is java.lang.String - internally it contains a mutable array that is written to while the String is constructed but never changed after that point.

Upvotes: 2

DaoWen
DaoWen

Reputation: 33019

In this form, yes, your class is immutable.

However, this is a trivial example and wouldn't actually be useful for anything since you can't access any of the internal data. The thing you need to be careful of is to not let any references to bOb escape from A. If you add a method which returns bOb, you need to return a copy of bOb to avoid accidentally allowing the caller to mutate any of the contents of A.

Upvotes: 1

gkuzmin
gkuzmin

Reputation: 2474

If bOb is a list and it contains mutable content, then not. But it seems that you use only int as content and this solves the problem.

Upvotes: 1

Related Questions