I know the usual reasons that apply to general immutable classes, viz
- can not change as a side effect
- easy to reason about their state
- inherently thread safe
- no need to provide clone/copy constructor/factory copy method
- instance caching
- no need for defensive copies.
However, wrapper classes represent primitive types, and primitive types are mutable. So why aren't wrapper classes mutable?
No they're not (and String isn't a primitive). But since primitive types aren't objects anyway, they can't really be called mutable / immutable in the first place.
Regardless, the fact the wrapper classes are immutable is a design decision (a good one IMO.) Thye could have just has easily been made mutable, or mutable alternatives provided too (indeed several libraries provide this, and other languages do by default.)
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
There are mutable, thread safe wrappers as well for some types.
Plus some exotic wrappers
The wrapper classes are immutable because it just makes no sense to be mutable.
Consider following code:
At first, it looks straightforward if you can change the value of N, just like you can change the value of n.
But actually N is not a wrapper to n, but a wrapper to 6! Look at the following line again:
You are actually passing the value of n, which is 6, to N. And since Java is pass-by-value, you cannot pass n into N, to make N a wrapper to n.
So, if we did add a set method to the wrapper:
The value of n will not be changed and that will be confusing!
Conclusion:
wrapper classes are wrappers of values, not wrappers of the variables.
it will be confusing if you did add a set method.
if you know it is a wrapper of a value, you will no longer ask for a set method. For example, you will not do "6.setValue(7)".
it's impossible to make a wrapper to a variable in Java.
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.
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:
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
andCalendar
were immutable far more often than I find myself wantingInteger
to be mutable... (Of course I normally reach for Joda Time instead, but one of the benefits of Joda Time is immutability.)