是不可变的

我知道这可能很愚蠢,但是很多地方声称 Java 中的 Integer 类是不可变的,但是下面的代码:

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

毫不费力地执行并给出(预期的)结果6。所以实际上 a 的值发生了变化。这不就意味着 Integer 是可变的吗? 第二个问题,有点跑题: “不可变类不需要复制构造函数”。有人愿意解释一下为什么吗?

79237 次浏览

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

a = new Integer(3 + 3)

所以,整数不是可变的,但是指向它们的变量是 * 。

* 可能有不可变的变量,这些变量由关键字 final表示,这意味着引用可能不会改变。

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

不可变并不意味着您不能更改变量的值。它只是意味着任何新的赋值都会创建一个新对象(分配给它一个新的内存位置) ,然后赋值给它。

要理解这一点,请在循环中执行 Integer 赋值(在循环外声明整数) ,并查看内存中的活动对象。

不可变对象不需要复制建构子的原因很简单,这是常识。由于每个赋值都会创建一个新对象,所以语言在技术上已经创建了一个副本,因此您不必创建另一个副本。

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没有改变,相反,str现在是一个全新的实例化对象,就像您的 Integer一样。因此,a的值并没有发生变化,而是被一个全新的对象所替换,即 new Integer(6)

是的,整数是不可变的。

是指向对象的引用。当运行 a + = 3时,将重新分配 A 以引用一个新的 Integer 对象,该对象具有不同的值。

您从未修改原始对象,而是将引用指向另一个对象。

Read about the difference between objects and references here.

“不可变类不需要复制构造函数”。有人能解释一下为什么吗?

原因是 很少需要复制(甚至复制过程中的任何一点)一个不可变类的实例。对象的副本应该是“相同的”原件,如果是相同的,应该没有必要创建它。

不过,有一些潜在的假设:

  • 它假定您的应用程序不会对类的实例的对象标识赋予任何意义。

  • 它假设类已经重载了 equalshashCode,因此一个实例的副本将与原来的“相同”... 根据这些方法。

这两个假设中的一个或两个都是错误的,因此可能需要增加一个复制建构子。

您可以使用 System.identityHashCode()确定对象已经更改(更好的方法是使用普通的 ==,但是引用而不是值的更改并不明显)

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

指纹

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

您可以看到 a引用的对象的底层“ id”已经更改。

对于最初提出的问题,

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

整数是不可变的,所以上面发生的是‘ a’变成了一个值为6的新引用。初始值3在内存中没有引用(它没有被更改) ,因此可以对其进行垃圾回收。

如果 String 发生这种情况,它将在池中(在 PermGen 空间中)保持比 Integers 更长的时间,因为它期望具有引用。

通过简单的示例代码,我可以清楚地说明 Integer (以及它的其他信条,如 Float、 Short 等)是不可变的:

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 嗨 There 100 instead of expected result (in case of both sb and i being mutable objects) 嗨,1000

这表明在 main 中由 i 创建的对象没有被修改,而 sb 被修改了。

So StringBuilder demonstrated mutable behavior but not Integer.

所以整数是不变的

另一个没有 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;
}




}

这就是我所理解的永恒

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.

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
}

产出为:

Hi 再见 1000 五千 1000 五千 d 一

所以 char 是可变的,String Integer 和 int 是不可变的。

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");

需要记住的是,现在有一个 Integer 值的缓存。它有时会使开发人员避免使用 = = 而不是。当从 int 变为 Integer 时,equals ()。但也不总是这样。实例化新 Integer 时,将创建一个新实例。因此整数不仅是不变的,而且是半静态的。

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

给出打印输出:

A-id: 666988784
B-id: 666988784
C-id: 1414644648
是的
A = = c: 假
A eq c: true < br >