我知道这可能很愚蠢,但是很多地方都声称Java中的Integer类是不可变的,但是下面的代码:
Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);
毫无困难地执行(给出预期的结果)6。因此有效地改变了a的值。这不是说Integer是可变的吗?第二个问题和一点题外话:“不变的类不需要复制构造函数”。有人在乎解释原因吗?
我知道这可能很愚蠢,但是很多地方都声称Java中的Integer类是不可变的,但是下面的代码:
Integer a=3;
Integer b=3;
a+=b;
System.out.println(a);
毫无困难地执行(给出预期的结果)6。因此有效地改变了a的值。这不是说Integer是可变的吗?第二个问题和一点题外话:“不变的类不需要复制构造函数”。有人在乎解释原因吗?
Answers:
不可变并不意味着a
永远不能等于另一个值。例如,String
也是不可变的,但我仍然可以这样做:
String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"
str
并没有改变,而是变成str
了一个完全新实例化的对象,就像您一样Integer
。因此,的值a
没有发生变化,而是由一个全新的对象代替new Integer(6)
。
+=
操作而实例化的对象。
Integer.valueOf(int)
和那个方法维护Integer
对象的缓存。因此,+=
on Integer
变量的结果可能是先前存在的对象(或者甚至可能是同一对象…… a += 0
)。
您可以使用确定对象是否已更改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” 已更改。
是整数是不可变的。
A是指向对象的参考。当您运行+ = 3时,它将重新分配A来引用具有不同值的新Integer对象。
您从未修改原始对象,而是将引用指向了另一个对象。
在此处阅读有关对象和引用之间的区别。
不可变并不意味着您不能更改变量的值。这只是意味着任何新分配都会创建一个新对象(为它分配一个新的内存位置),然后将值分配给它。
要自己了解这一点,请在循环中执行Integer分配(在循环外部声明整数),然后查看内存中的活动对象。
不可变对象不需要复制构造函数的原因很简单。由于每个分配都会创建一个新对象,因此该语言在技术上已经创建了一个副本,因此您不必创建另一个副本。
我可以通过简单的示例代码明确指出Integer(以及其他信条,例如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");
}
}
实际结果
结果显示为Hi There 100,而不是预期结果(如果sb和i都是易变对象)Hi There 1000
这表明i在main中创建的对象未修改,而sb已修改。
因此,StringBuilder表现出可变的行为,但没有表现出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;
}
}
private void doStringBuilder(StringBuilder sb){ sb = new StringBuilder(); }
则sb
保持不变。
private void doInteger(Integer i){ System.out.println( i == 100 ); i=1000; System.out.println( i == 100 ); }
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
}
输出为:
嗨再见1000 5000 1000 5000 d a
因此char是可变的,String Integer和int是不可变的。