整数是不可变的

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

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

执行没有任何麻烦给予(预期)的结果6.如此有效的价值已经改变。 这不是说整数是可变的吗? 次要的问题和一些小题目:“不可变类不需要拷贝构造函数”。 任何人都在意解释为什么?

不可变并不意味着a永远不能等于另一个值。 例如, String也是不可变的,但我仍然可以这样做:

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

那么发生了什么? 由于String是不可变的,显然str没有改变。 但是现在等于不同的东西。 这是因为str现在是一个完全新实例化的对象,就像Integer 。 所以a的值没有变化,但被一个全新的对象,即new Integer(6)所取代。

a是一个Integer(3)的“引用”,你的简写a+=b真的意味着这样做:

 a = new Integer(3 + 3) 

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

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

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

你可以使用System.identityHashCode()来确定对象已经改变了(更好的方法是使用plain ==但是它不像引用那样明显,而不是值已经改变了)

 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空间中)比整数更长的时间段,因为它期望有引用。

是整数是不可变的。

A是指向一个对象的引用。 当你运行一个+ = 3的时候,它会重新赋值A来引用一个新的Integer对象,其值不同。

你永远不会修改原始对象,而是指向不同对象的引用。

阅读这里的对象和引用之间的区别。

不可变并不意味着你不能改变一个variables的值。 这只是意味着任何新的赋值都会创build一个新的对象(赋予它一个新的内存位置),然后赋值给它。

为了自己理解这一点,在一个循环中执行整数赋值(使用在循环外部声明的整数)并查看内存中的活动对象。

不可变对象不需要拷贝构造函数的原因是简单的常识。 由于每个作业都创build一个新的对象,因此该语言在技术上已经创build了一个副本,因此您不必创build另一个副本。

“不可变类不需要拷贝构造函数”。 任何人都在意解释为什么?

原因是很less有任何需要复制(甚至是复制)不可变类的实例。 对象的副本应该与原来的“相同”,如果相同,则不需要创build它。

但是有一些基本的假设:

  • 它假设你的应用程序不会对类的实例的对象标识有任何意义。

  • 它假设类已经重载了equalshashCode以便根据这些方法实例的副本将与原来的“相同”。

这些假设中的任何一个或两个都可能是错误的,这可能需要添加一个拷贝构造函数。

我可以清楚地看到整数(和其他的信条,如Float,Short等)通过简单的示例代码是不可变的:

示例代码

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

实际结果

结果来到他嗨有100而不是预期的结果(在情况下,sb和我是可变的对象) 嗨有1000

这显示我在main中创build的对象没有被修改,而sb被修改。

所以StringBuilder演示了可变行为,但不是整数。

所以Integer是不变的。 因此certificate

另一个不带整数的代码:

 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 

如果int可能发生变化,“a”会打印8,但不是因为它是不可变的,所以它是3.你的例子只是一个新的任务。

 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 Bye 1000 5000 1000 5000 d a

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