Why is this class considered mutable?

662 views Asked by At
public class A {
    private int[] values;

    public int[] getValues() {
        return values;
    }
}

A book that I'm reading says that it is not immutable because values is a reference type. I see no way to mutate values other than creating a main method inside of the class.

4

There are 4 answers

7
Mario F On BEST ANSWER

It is mutable because you can change the contents of values through the method that you exposed

A obj = new A(...) // values gets filled here
int[] leak = obj.getValues()
leak[0] = 42

This would mean that your values property contains now information that has been modified externally. To make it immutable, you should return a copy of the array, so that you are sure no external agent can modify it, and you should make it final, so that no subclasses can be created that can expose the state and make it mutable again:

public final class A {
  private int[] values;

  public int[] getValues() {
    return Arrays.copyOf(values);
  }
}
2
egorlitvinenko On

You can get reference and change element array:

 A.getValues()[0] = -100500

You can use reflection to change values field, or somewhere else (probably author means) or with inheritance as showed below.

For instance,

Immutable class:

import java.util.Arrays;

public final class A {
    private int[] values;

    public int[] getValues() {
        return values;
    }
}

Immutable object:

import java.util.Arrays;

public class A {
    private final int[] values;

    public A(int[] values) {
        this.values = null == values ? null : Arrays.copyOf(values);
    }

    public int[] getValues() {
        return Arrays.copyOf(values);
    }
}

Immutable class and object:

import java.util.Arrays;

public final class A {
    private final int[] values;

    public A(int[] values) {
        this.values = null == values ? null : Arrays.copyOf(values);
    }

    public int[] getValues() {
        return Arrays.copyOf(values);
    }
}
16
Andy Turner On

It's not actually mutable through the values array, as stated in other answers: that array is null, as it is never initialized, and you can't make it non-null via the result of the getter.

It's mutable because you can subclass it, and add mutable state:

class AA extends A {
  String foo;
}

AA aa = new AA();
aa.foo = "foo";
A a = aa;
aa.foo = "bar";  // Mutates the state of a.

Note that there is a "Strategy for defining immutable objects" in the Oracle Java tutorial, as well as a list of requiried properties of immutable objects in Effective Java 2nd Ed Item 15: "Minimize mutability".

0
Calvin Li On

values, being an array is a reference type. You can find out more about references here. This means that when getValues() returns values, it's actually returning a pointer to it (that gets dereferenced every time, since Java doesn't have explicit pointers). Although the reference itself cannot be reassigned since values is private, the contents can be changed.

So something like a.getValues()[0]++ will increment the first element of values, assuming it isn't empty.