25

I know the usual reasons that apply to general immutable classes, viz

  1. can not change as a side effect
  2. easy to reason about their state
  3. inherently thread safe
  4. no need to provide clone/copy constructor/factory copy method
  5. instance caching
  6. no need for defensive copies.

However, wrapper classes represent primitive types, and primitive types are mutable. So why aren't wrapper classes mutable?

shrini1000
  • 7,038
  • 12
  • 59
  • 99

9 Answers9

33

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.)

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    I would argue that 'int x = 5; x = 6;' is changing value of *x*, hence 'int' primitive type is mutable. – shrini1000 Sep 11 '12 at 13:22
  • 3
    @shrini1000, you have right as far it goes for memory allocation. But in Java you can not read/write directly from/to memory. Therefore as Jon Skeet wrote it make no sence to call primitives mutable or inmutable because of the way you must work with them. – Damian Leszczyński - Vash Sep 11 '12 at 13:38
  • 8
    @shrini1000: You agree that strings are immutable, right? But if you wrote `String x = "hello"; x = "there";` that wouldn't make them mutable, would it? Changing the value of a variable isn't the same thing as making that value change itself. – Jon Skeet Sep 11 '12 at 13:40
  • Jon Skeet, @Vash, agreed. Thanks for that nice example. – shrini1000 Sep 11 '12 at 13:48
  • Btw, just thought of this: String isn't primitive, so would your example be applicable here? :) But I understand the point you're making, and accept it. – shrini1000 Sep 11 '12 at 13:55
  • @shrini1000: My point is that your definition of "mutable" seemed to include `int` but not `String`, despite them behaving the same way in this respect. – Jon Skeet Sep 11 '12 at 14:28
  • Immutable `Calendar` (as per java API) would make absolutely no sense. `Calendar` is a computation class. `Date` makes little sense to be mutable nowadays but there was no Calendar and the state mutation cannot be abandoned. I actually use `ImmutableDate extends Date` in the middleware to avoid copying and clone() is implemented as `return this`. `long` is immutable though. – bestsss Sep 12 '12 at 15:17
  • 1
    @bestsss: Well Calendar is a mixture of computation and state. That's half the problem. In Joda Time the two are separated, which is much better. Making an immutable type extend a mutable one breaks LSP IMO. Anything expecting to treat it like a normal `Date` using `setTime` etc will fail. – Jon Skeet Sep 12 '12 at 16:03
  • @Jon, of course it will fail and that's the idea, no such code shall be in production. Since we own the stack, it's not a hard rule to enforce and honestly I have not seen code that actually uses setTime/Date/Minute/etc. – bestsss Sep 12 '12 at 16:31
  • @bestsss: I've seen plenty of code using `setTime`, which isn't deprecated. I still prefer Joda Time though :) – Jon Skeet Sep 12 '12 at 16:44
  • True, `setTime` is not deprecated.It's really hard to imagine why anyone will use it on a passed parameter, though. – bestsss Sep 12 '12 at 16:50
  • @shrini1000: As per my knowledge, Integral wrapper classes maintains buffer ranging from -127 to +127. Whenever we are creating object in between [-127 to +127] with integral wrapper class it points to the buffer object. Buffer works as String Constant Pool in wrapper classes. – Shrirang Kadale Jan 25 '19 at 05:05
  • @ShrirangKadale: It's a cache of *at least* that - it can be larger. – Jon Skeet Jan 25 '19 at 06:48
15

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
Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130
  • 1
    Stamped and Markable suck though as there are no intrinsics for, esp. for the Markable, it'd be an awesome class if the bits in the reference/pointer were actually used. (Pointer/References may have some unused bits like in CMS uses them). Stamped can be implemeted as 32pointer+32int and take 64 bit CAS, or 64bit and 32bit and 128bit CAS, alas they allocate like mad. – bestsss Sep 12 '12 at 15:20
11

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.

Philipp
  • 67,764
  • 9
  • 118
  • 153
  • But isn't it the same case where you allow a reference to a private mutable object to leak out? A way to fix it would be to use defensive copying and validation. – shrini1000 Sep 11 '12 at 13:26
  • 1
    Yes, it is. That's why immutable objects are generally not a bad idea, as long as they are feasible. – Philipp Sep 11 '12 at 13:27
  • 1
    Agreed, however what I meant was, the issue you point out is applicable to all mutable objects in general and not only to possibly mutable wrapper objects. – shrini1000 Sep 11 '12 at 13:30
  • Thanks for the example – sid_09 May 20 '17 at 19:23
  • This is simple to fix, just change second line to `private int value;` – Maciej Łoziński Jan 04 '18 at 11:13
  • 1
    @MaciekŁoziński The question is specifically about the wrapper classes for primitive types. "Just don't use them" wouldn't be an appropriate answer, because there are situations where you have not other choice. – Philipp Jan 04 '18 at 11:22
  • Hi @Philipp, I understand the code you have included. By changing, 'i' it would change the values on foo1, foo2, foo3. But, I don't get what's the downside here? why can't an user do '++i' and make the values change on all objects, won't that be a useful case? Sorry, I am beginner developer, maybe I am missing a bigger picture here? – william cage Jun 06 '20 at 22:16
6

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

Sean Patrick Floyd
  • 292,901
  • 67
  • 465
  • 588
4

However, wrapper classes represent primitive types, and primitive types (except String) are mutable.

No they're not (and String isn't a primitive type). But since primitive types aren't objects anyway, they can't really be called mutable / immutable in the first place.

Regardless, the fact that wrapper classes are immutable is a design decision (a good one IMO.) They could have just has easily been made mutable, or mutable alternatives provided too (indeed several libraries provide this, and other languages do by default.)

Michael Berry
  • 70,193
  • 21
  • 157
  • 216
4

The wrapper classes are immutable because it just makes no sense to be mutable.

Consider following code:

int n = 5;
n = 6;
Integer N = new Integer(n);

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:

Integer N = new Integer(n);

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:

Integer N = new Integer(n);
N.setValue(7);
print(N); // ok, now it is 7
print(n); // oops, still 6!

The value of n will not be changed and that will be confusing!

Conclusion:

  1. wrapper classes are wrappers of values, not wrappers of the variables.

  2. it will be confusing if you did add a set method.

  3. 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)".

  4. it's impossible to make a wrapper to a variable in Java.

Henry
  • 942
  • 3
  • 11
  • 21
3

Any object instance which has any mutable aspects must have a unique identity; otherwise, another object instances which at one moment happened to be identical in every way except for its identity might at some other moment be different in its mutable aspect. In many cases, though, it's useful for types not to have an identity--to be able to pass a "4" without having to worry about which "4" one is passing. While there are times when it may be helpful to have a mutable wrapper of a primitive or immutable type, there are many more times when it's useful to have a type where all instances that hold the same data at some moment in time may be regarded as interchangeable.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

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.

Scooter
  • 6,802
  • 8
  • 41
  • 64
0

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.

Vipin Jain
  • 3,686
  • 16
  • 35