Are Java primitives immutable?

If a method has a local variable i:

int i = 10;

and then I assign a new value:

i = 11;

Will this allocate a new memory location? Or just replace the original value?

Does this mean that primitives are immutable?


Solution 1:

Will this allocate a new memory location? Or just replace the original value?

Java does not really make any guarantees that variables will correspond to memory locations; for example, your method might be optimized in such a way that i is stored in a register — or might not even be stored at all, if the compiler can see that you never actually use its value, or if it can trace through the code and use the appropriate values directly.

But setting that aside . . . if we take the abstraction here to be that a local variable denotes a memory location on the call stack, then i = 11 will simply modify the value at that memory location. It will not need to use a new memory location, because the variable i was the only thing referring to the old location.

Does this mean that primitives are immutable?

Yes and no: yes, primitives are immutable, but no, that's not because of the above.

When we say that something is mutable, we mean that it can be mutated: changed while still having the same identity. For example, when you grow out your hair, you are mutating yourself: you're still you, but one of your attributes is different.

In the case of primitives, all of their attributes are fully determined by their identity; 1 always means 1, no matter what, and 1 + 1 is always 2. You can't change that.

If a given int variable has the value 1, you can change it to have the value 2 instead, but that's a total change of identity: it no longer has the same value it had before. That's like changing me to point to someone else instead of to me: it doesn't actually change me, it just changes me.

With objects, of course, you can often do both:

StringBuilder sb = new StringBuilder("foo");
sb.append("bar"); // mutate the object identified by sb
sb = new StringBuilder(); // change sb to identify a different object
sb = null; // change sb not to identify any object at all

In common parlance, both of these will be described as "changing sb", because people will use "sb" both to refer the variable (which contains a reference) and to the object that it refers to (when it refers to one). This sort of looseness is fine, as long as you remember the distinction when it matters.

Solution 2:

Immutable means that each time the value of and object has changed a new reference is created for it on stack. You can't talk about immutability in case of primitive types,only the Wrapper Classes are immutable. Java uses copy_by_value not by reference.

It makes no difference if you're passing primitive or reference variables, you are always passing a copy of the bits in the variable. So for a primitive variable, you're passing a copy of the bits representing the value and if you're passing an object reference variable, you're passing a copy of the bits representing the reference to an object.

For example, if you pass an int variable with the value of 3, you're passing a copy of the bits representing 3.

Once a primitive has been declared, its primitive type can never change, although its value can change.

Solution 3:

Let's take a step further and add another variable j in it.

int i = 10;
int j = i;
i = 11

In java 8 byte of memory is allocated for value of i and j (4 byte for i and 4 byte for j). The value of i is passed to j and now j and i have same value but different memory address. Now value of i is changed to 11 meaning for same memory address the value of i is changed from 10 to 11 but value of j is in different memory location and so it remains as 10.

enter image description here

In case of objects the value(or reference) itself is an address(or heap address) so if one changes it, it will be reflected for others as well. For example in objects :-

Person p1 = new Person();
Person p2 = p1;

enter image description here

So either p1 make changes or p2 make changes it will be changed for both. Whether it is Java, Python or Javascript it is same. In case of primitive it is the actual value but in case of objects it is a address of actual object - that's the trick.

Solution 4:

This isn't a full answer, but it is a way to prove the immutability of primitive-type values.

If primitive values (literals) are mutable, then the following code would work fine:

int i = 10; // assigned i the literal value of 10
5 = i; // reassign the value of 5 to equal 10
System.out.println(5); // prints 10

Of course, this isn't true.

The integer values, such as 5, 10 and 11 are already stored in the memory. When you set a variable equal to one of them: it changes the value in the memory-slot where i is.

You can see this here through the bytecode for the following code:

public void test(){
    int i = 10;
    i = 11;
    i = 10;
}

Bytecode:

// access flags 0x1
public test()V
 L0
  LINENUMBER 26 L0
  BIPUSH 10 // retrieve literal value 10
  ISTORE 1  // store it in value at stack 1: i
 L1
  LINENUMBER 27 L1
  BIPUSH 11 // same, but for literal value 11
  ISTORE 1
 L2
  LINENUMBER 28 L2
  BIPUSH 10 // repeat of first set. Still references the same literal 10. 
  ISTORE 1 
 L3
  LINENUMBER 29 L3
  RETURN
 L4
  LOCALVARIABLE this LTest; L0 L4 0
  LOCALVARIABLE i I L1 L4 1
  MAXSTACK = 1
  MAXLOCALS = 2

As you can see in the bytecode (hopefully) it references the literal value (example: 10) and then stores it in the slot for variable i. When you change the value of i, you are just changing which value is stored in that slot. The values themselves aren't changing, the location of them is.