开发者

Is Integer Immutable

开发者 https://www.devze.com 2023-02-22 21:33 出处:网络
I know this is probably very stupid, but a lot of places claim that the Integer class in Java is immutable, yet the following code:

I know this is probably very stupid, but a lot of places claim that the Integer class in Java is immutable, yet the following code:

Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);

Executes without any trouble giving the (expected) result 6. So effectively the value of a has changed. Doesn't that mean Integer is mutable? Secondary开发者_运维技巧 question and a little offtopic: "Immutable classes do not need copy constructors". Anyone care to explain why?


Immutable does not mean that a can never equal another value. For example, String is immutable too, but I can still do this:

String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"

str was not changed, rather str is now a completely newly instantiated object, just as your Integer is. So the value of a did not mutate, but it was replaced with a completely new object, i.e. new Integer(6).


a is a "reference" to some Integer(3), your shorthand a+=b really means do this:

a = new Integer(3 + 3)

So no, Integers are not mutable, but the variables that point to them are*.

*It's possible to have immutable variables, these are denoted by the keyword final, which means that the reference may not change.

final Integer a = 3;
final Integer b = 3;
a += b; // compile error, the variable `a` is immutable, too.


You can determine that the object has changed using System.identityHashCode() (A better way is to use plain == however its not as obvious that the reference rather than the value has changed)

Integer a = 3;
System.out.println("before a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));
a += 3;
System.out.println("after a +=3; a="+a+" id="+Integer.toHexString(System.identityHashCode(a)));

prints

before a +=3; a=3 id=70f9f9d8
after a +=3; a=6 id=2b820dda

You can see the underlying "id" of the object a refers to has changed.


To the initial question asked,

Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);

Integer is immutable, so what has happened above is 'a' has changed to a new reference of value 6. The initial value 3 is left with no reference in the memory (it has not been changed), so it can be garbage collected.

If this happens to a String, it will keep in the pool (in PermGen space) for longer period than the Integers as it expects to have references.


Yes Integer is immutable.

A is a reference which points to an object. When you run a += 3, that reassigns A to reference a new Integer object, with a different value.

You never modified the original object, rather you pointed the reference to a different object.

Read about the difference between objects and references here.


Immutable does not mean that you cannot change value for a variable. It just means that any new assignment creates a new object ( assigns it a new memory location) and then the value gets assigned to it.

To understand this for yourself, perform Integer assignment in a loop ( with integer declared outside the loop ) and look at the live objects in memory.

The reason why copy constructor is not needed for immutable objects is simple common sense. Since each assignment creates a new object, the language technically creates a copy already, so you do not have to create another copy.


This is how I understand immutable

int a=3;    
int b=a;
b=b+5;
System.out.println(a); //this returns 3
System.out.println(b); //this returns 8

If int could mutate, "a" would print 8 but it does not because it is immutable, thats why it is 3. Your example is just a new assignment.


"Immutable classes do not need copy constructors". Anyone care to explain why?

The reason is that there is rarely any need to copy (or even any point in copying) an instance of a immutable class. The copy of the object should be "the same as" the original, and if it is the same, there should be no need to create it.

There are some underlying assumptions though:

  • It assumes that your application does not place any meaning on the object identity of instances of the class.

  • It assumes that the class has overloaded equals and hashCode so that a copy of an instance would be "the same as" the original ... according to these methods.

Either or both of those assumptions could be false, and that might warrant the addition of a copy constructor.


I can make clear that Integer (and other of its creed like Float, Short etc) are immutable by simple sample code:

Sample Code

public class Test{
    public static void main(String... args){
        Integer i = 100;
        StringBuilder sb = new StringBuilder("Hi");
        Test c = new Test();
        c.doInteger(i);
        c.doStringBuilder(sb);
        System.out.println(sb.append(i)); //Expected result if Integer is mutable is Hi there 1000
    }

    private void doInteger(Integer i){
        i=1000;
    }

    private void doStringBuilder(StringBuilder sb){
        sb.append(" there");
    }

}

Actual Result

The result comes to he Hi There 100 instead of expected result (in case of both sb and i being mutable objects) Hi There 1000

This shows the object created by i in main is not modified, whereas the sb is modified.

So StringBuilder demonstrated mutable behavior but not Integer.

So Integer is Immutable. Hence Proved

Another code without only Integer:

public class Test{
    public static void main(String... args){
        Integer i = 100;
        Test c = new Test();
        c.doInteger(i);
        System.out.println(i); //Expected result is 1000 in case Integer is mutable
    }

    private void doInteger(Integer i){
        i=1000;
    }


}


public static void main(String[] args) {
    // TODO Auto-generated method stub

    String s1="Hi";
    String s2=s1;

    s1="Bye";

    System.out.println(s2); //Hi  (if String was mutable output would be: Bye)
    System.out.println(s1); //Bye

    Integer i=1000;
    Integer i2=i;

    i=5000;

    System.out.println(i2); // 1000
    System.out.println(i); // 5000

    int j=1000;
    int j2=j;

    j=5000;

    System.out.println(j2); // 1000
    System.out.println(j); //  5000


    char c='a';
    char b=c;

    c='d';

    System.out.println(c); // d
    System.out.println(b); // a
}

Output is :

Hi Bye 1000 5000 1000 5000 d a

So char is mutable , String Integer and int are immutable.


Copy and run this code,I hope this will answer all your doubts

private static void wrapperClassDemo() {
    //checking wrapper class immutability using valueOf method
    //We can create wrapper class by using either "new" keyword or using a static method "valueOf()"
    //The below Example clarifies the immutability concept of wrapper class in detail
    //For better understanding just ciopy the below code to the editor and run
        
    Integer num1 =Integer.valueOf(34);  // i'm passing the 34 as the parameter to the valueOf method
    System.out.println("value assigned to num1 is : "+num1);
    System.out.println("Printing the hashcode assigned to store the \" num1 \"value in memory: "+System.identityHashCode(num1));
        
    Integer num2 =Integer.valueOf(34);
    System.out.println("value assigned to num2 is : "+num2);
    System.out.println("Printing the hashcode assigned to store the \" num2 \"value in memory: "+System.identityHashCode(num2));
        
    /*Now u can notice both the hashcode value of num1 and num2 are same. that is because once you created the num1 with the value 34 an object is 
     * created in the heap memory. And now You are passing the value  same as num1 to the num2 .Now JVM Checks the same value is present in the heap Mmeomry
     * If present the reference variable(in this example it is num2) will  be pointed to the same address where the object num1 is stored so u get the same hashcode         */
         
        
    num2++; // You can use num2 = 35 as both are same; 
    System.out.println("\nvalue assigned to num2 is : "+num2);
    System.out.println("Printing the hashcode of  \" num1 \": "+System.identityHashCode(num1) + "\nPrinting the hashcode of  \" num2 \": "+System.identityHashCode(num2));
    System.out.println("As now you can notice the hashcode has changed for num2 ,That is because now a new object is created for num2 and it is referencing the new object");
        
    //Again i'm incrementing num2
    System.out.println("\nBefore incremeting  the hashcode of  \" num2 \" is: "+System.identityHashCode(num2));
    num2++; // You can use num2 = 36 as both are same;
    System.out.println("After incremeting  the hashcode of  \" num2 \" is: "+System.identityHashCode(num2));
    //now the hashcode value of num2 is changed ,again new object is created for the updated value and num2 is referencing new object ,and old object will be garbage collected
        
    System.out.println("\n Thus the CONCLUSION is Wrapper objects are immutable ,They only create new object and refernce the new object ,They won't modify the present object ");
    System.out.println("This is applicable for Strings also");


Something to hold in mind is that there is now a cache for Integer values. It sometimes saves developers from the mistake of using == instead of .equals() when changing from int to Integer. Not always though. When you instantiate a new Integer, there will be a new instance created. So Integers are not only immutable, but also semi static.

    Integer a = 3;
    Integer b = 3;
    Integer c = new Integer(3);
    b = b + 1;
    b = b - 1;

    System.out.println("a-id: " + System.identityHashCode(a));
    System.out.println("b-id: " + System.identityHashCode(b));
    System.out.println("c-id: " + System.identityHashCode(c));
    System.out.println("a == b: " + (a == b));
    System.out.println("a == c: " + (a == c));
    System.out.println("a eq c: " + (a.equals(c)));    

Gives the printout:

a-id: 666988784
b-id: 666988784
c-id: 1414644648
a == b: true
a == c: false
a eq c: true

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号