tags:

views:

258

answers:

4

Hi,

Is the below class immutable:

final class MyClass {
    private final int[] array;
    public MyClass(int[] array){
        this.array = array;
    }
}
+15  A: 

No it is not because the elements of the array can still be changed.

int[] v1 = new int[10];
MyClass v2 = new MyClass(v1);
v1[0] = 42;  // mutation visible to MyClass1
JaredPar
How? Via reflection?
Vivin Paliath
@Vivin added a code sample
JaredPar
Ah right! I keep forgetting that the reference is assigned to the private member.
Vivin Paliath
A nice read-only array wrapper would solve this problem.
ChaosPandion
@Chaos: It couldn't be a wrapper. It would have to take a copy of the passed in array. It can't wrap anything that the original caller could still mutate.
Jon Skeet
@Jon - A simple semantic faux pas is all. My mistake was in thinking that a copy was implied.
ChaosPandion
You have to keep all references to that array internal. You could allow retrieving of individual elements without returning the entire array or you could program using OO methodologies by placing code that needs to access the array inside this class itself, making it both immutable AND OO.
Bill K
A: 

There is no way to make an array immutable. That is there is no way to keep any client code from setting or removing or adding items to the array.

Here is a truly immutable alternative:

private static class MyClass
{
    private List<Integer> list;

    private MyClass(final int[] array)
    {
        final List<Integer> tmplist = new ArrayList<Integer>(array.length);
        for (int i : array)
        {
            tmplist.add(array[i]);
        }
        this.list = Collections.unmodifiableList(tmplist);
    }
}
fuzzy lollipop
No, both unmodifiableList and asList create views. Thus external changes to the array like in JaredPar's answer will cause changes in this version of MyClass.
ILMTitan
`Arrays.asList(array)` will also return a `List<int[]>`.
Tom Hawtin - tackline
who ever downvoted doesn't understand the immutable contract.if you return a data structure that can be changed, regardless if it is a COPY of some backing array it is still __NOT__ immutable. Making a clone of something and returning a mutable clone does __NOT__ make a class 100% immutable, it also violates the principal of least astonishment. asList does __NOT__ create a "view" it creates a __MUTABLE__ copy of an array as a List. Unmodifiable is just that, it returns a list that is not modifiable, and thus immutable.
fuzzy lollipop
The lesson here is __NOT__ to use arrays and use an appropriate Collection class to begin with.
fuzzy lollipop
+4  A: 

My two cents regarding immutability rules (which I retained from reading Effective Java - a great book!):

  1. Don't provide methods that can modify the state of an object.
  2. Make all your fields final.
  3. Make sure that your class is non-extendable.
  4. Make all your fields private.
  5. Provide exclusive access to any fields or components of your class that can be changed. Essentially this applies to your situation (as explained by JaredPar). A person that uses your class still has a reference to your array. The opposite is the case where you return a reference to an component of your class. In this case, always create defensive copies. In your case, you should not assign the reference. Instead, copy the array that the user of your class provides, into your internal component.
Vivin Paliath
And don't implement `Serializable`.
Tom Hawtin - tackline
A: 

"Immutability" is a convention between the programmer and himself. That convention may be more or less enforced by the compiler.

Instances of a class are "immutable" if they do not change during the normal course of the application code execution. In some cases we know that they do not change because the code actually forbids it; in other cases, this is just part of how we use the class. For instance, a java.util.Date instance is formally mutable (there is a setTime() method on it) but it is customary to handle it as if it were immutable; this is just an application-wide convention that the Date.setTime() method shall not be called.

As additional notes:

  • Immutability is often thought of in terms of "external characteristics". For instance, Java's String is documented to be immutable (that's what the Javadoc says). But if you look at the source code, you will see that a String instance contains a private field called hash which may change over time: this is a cache for the value returned by hashCode(). We still say that String is immutable because the hash field is an internal optimization which has no effect visible from the outside.
  • With reflection, the most private of instance fields can be modified (including those marked as final), if the programmer wishes so hard enough. Not that it is a good idea: it may break assumptions used by other pieces of code using the said instance. As I said, immutability is a convention: if the programmer wants to fight himself, then he can, but this can have adverse side-effects on productivity...
  • Most Java values are actually references. It is up to you to define whether a referenced object is part of what you consider to be "the instance contents". In your class, you have a field which references an (externally provided) array of integers. If the contents of that array are modified afterwards, would you consider that this breaks immutability of your MyClass instance ? There is no generic answer to that question.
Thomas Pornin