整数是不可变的
我知道这可能是非常愚蠢的,但很多地方声称在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它。
但是有一些基本的假设:
-
它假设你的应用程序不会对类的实例的对象标识有任何意义。
-
它假设类已经重载了
equals
和hashCode
以便根据这些方法实例的副本将与原来的“相同”。
这些假设中的任何一个或两个都可能是错误的,这可能需要添加一个拷贝构造函数。
我可以清楚地看到整数(和其他的信条,如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是不可变的。