I know the usual reasons that apply to general immutable classes, viz
For example, consider the following java program:
class WhyMutable
{
public static void main(String[] args)
{
String name = "Vipin";
Double sal = 60000.00;
displayTax(name, sal);
}
static void displayTax(String name, Double num) {
name = "Hello " + name.concat("!");
num = num * 30 / 100;
System.out.println(name + " You have to pay tax $" + num);
}
}
Result: Hello Vipin! You have to pay tax $18000.0
This is the case with pass by reference of wrapper class parameters as well. And, if strings and wrapper classes are non-final, anybody can extend those classes and write their own code to modify the wrapped primitive data. So, in order to maintain Data Integrity, the variables which we are using for data storage must be read-only,
i.e., Strings and Wrapper classes must be final & immutable and “pass by reference” feature should not be provided.
There are mutable, thread safe wrappers as well for some types.
AtomicBoolean
AtomicInteger
AtomicIntegerArray
AtomicLong
AtomicLongArray
AtomicReference - can wrap a String.
AtomicReferenceArray
Plus some exotic wrappers
AtomicMarkableReference - A reference and boolean
AtomicStampedReference - A reference and int
However, wrapper classes represent primitive types, and primitive types (except String) are mutable.
Firstly, String isn't a primitive type.
Secondly, it makes no sense to talk about the primitive types being mutable. If you change the value of a variable like this:
int x = 5;
x = 6;
That's not changing the number 5 - it's changing the value of x
.
While the wrapper types could have been made mutable, it would have been annoying to do so, in my view. I frequently use readonly collections of these types, and wouldn't want them to be changeable. Very occasionally I want a mutable equivalent, but in that case it's easy enough to come up with one, or use the Atomic*
classes.
I find myself wishing that Date
and Calendar
were immutable far more often than I find myself wanting Integer
to be mutable... (Of course I normally reach for Joda Time instead, but one of the benefits of Joda Time is immutability.)
For your info: if you want mutable holder classes, you can use the Atomic* classes in the java.util.concurrent
package, e.g. AtomicInteger
, AtomicLong
The primitive types are mutable, but they are not shareable - that is no two sections of code will ever be referring to the same int variable (they are always passed by value). So you can change your copy and no one else sees the change, and vice versa. As Phillip shows in his answer, that would not be the case with mutable wrapper classes. So my guess is that they had a choice when the wrapped the primitive data types between:
matching the fact that you can change the value of a primitive type,
versus
matching the fact that primitive types can be passed around and no changes by a user will be seen by any other user of the data.
And they chose the latter, which required immutability.
Here is an example where it would be quite bad when Integer would be mutable
class Foo{
private Integer value;
public set(Integer value) { this.value = value; }
}
/* ... */
Foo foo1 = new Foo();
Foo foo2 = new Foo();
Foo foo3 = new Foo();
Integer i = new Integer(1);
foo1.set(i);
++i;
foo2.set(i);
++i;
foo3.set(i);
Which are the values of foo1, foo2 and foo3 now? You would expect them to be 1, 2 and 3. But when Integer would be mutable, they would now all be 3 because Foo.value
would all point to the same Integer object.