整数是不可改变的

时间:2011-04-06 00:27:37

标签: java immutability mutable

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

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

执行(预期)结果时没有任何问题6.因此,a的值有效地发生了变化。这不意味着Integer是可变的吗? 次要问题和一点offtopic:“不可变类不需要复制构造函数”。有人在乎解释原因吗?

12 个答案:

答案 0 :(得分:87)

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

String str = "hello";
// str equals "hello"
str = str + "world";
// now str equals "helloworld"
那么那里发生了什么?由于String是不可变的,因此str显然没有改变。但它现在等于不同的东西。这是因为str现在是一个完全新实例化的对象,就像您的Integer一样。所以a的值没有变异,但它被一个全新的对象取代,即new Integer(6)

答案 1 :(得分:48)

a是某个整数(3)的“引用”,你的速记a+=b实际上意味着这样做:

a = new Integer(3 + 3)

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

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

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

答案 2 :(得分:17)

您可以使用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”已更改。

答案 3 :(得分:10)

对于最初提出的问题,

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

整数是不可变的,所以上面发生的是'a'已经改变为值6的新引用。初始值3在内存中没有引用(它没有被更改),所以它可以是垃圾收集。

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

答案 4 :(得分:7)

是整数是不可变的。

A是指向对象的参考。运行+ = 3时,会重新分配A以引用具有不同值的新Integer对象。

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

了解对象和参考文献here之间的区别。

答案 5 :(得分:3)

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

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

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

答案 6 :(得分:2)

  

“不可变类不需要复制构造函数”。有人在乎解释原因吗?

原因是很少需要复制(甚至复制任何一点)不可变类的实例。对象的副本应与原始副本“相同”,如果相同,则不需要创建它。

但有一些潜在的假设:

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

  • 它假设该类已重载equalshashCode,因此根据这些方法,实例的副本将与原始实例“相同”。

其中一个或两个假设可能是假的,这可能需要添加一个复制构造函数。

答案 7 :(得分:1)

这就是我理解不可变的方式

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.你的例子只是一个新的任务。

答案 8 :(得分:0)

我可以通过简单的示例代码明确表示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都是可变对象)你好1000

这表明i中创建的对象未被修改,而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;
    }


}

答案 9 :(得分:0)

复制并运行此代码,希望这能回答您的所有疑问

rotationBy(360f)

答案 10 :(得分:0)

需要记住的是,现在有一个整数值的缓存。当从 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 == b: 真
a == c: 假
a eq c: true

答案 11 :(得分:-1)

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 一个

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