Java原语是不可变的吗?

2022-08-31 17:31:11

如果方法具有局部变量:i

int i = 10;

然后我分配一个新值:

i = 11;

这会分配新的内存位置吗?或者只是替换原始值?

这是否意味着原语是不可变的?


答案 1

这会分配新的内存位置吗?或者只是替换原始值?

Java并没有真正保证变量将对应于内存位置;例如,您的方法可能以存储在寄存器中的方式进行优化,或者甚至可能根本不存储,如果编译器可以看到您从未实际使用过其值,或者如果它可以通过代码跟踪并直接使用适当的值。i

但撇开这一点...如果我们把这里的抽象理解为局部变量表示调用堆栈上的内存位置,那么将简单地修改该内存位置的值。它不需要使用新的内存位置,因为变量是唯一引用旧位置的东西。i = 11i

这是否意味着原语是不可变的?

是和否:是的,原语是不可变的,但是不,这不是因为上述原因。

当我们说某件事是可变的时,我们的意思是它可以被变异:改变,同时仍然具有相同的身份。例如,当你长出头发时,你正在改变自己:你仍然是你自己,但你的一个属性是不同的。

在原语的情况下,它们的所有属性完全由它们的身份决定; 总是意味着,无论如何,并且总是。你无法改变这一点。111 + 12

如果给定的变量具有值,则可以将其更改为具有该值,但这是标识的完全更改:它不再具有与以前相同的值。这就像改变指向别人而不是我:它实际上并没有改变,它只是改变了。int12meme

当然,对于对象,您通常可以同时执行这两项操作:

StringBuilder sb = new StringBuilder("foo");
sb.append("bar"); // mutate the object identified by sb
sb = new StringBuilder(); // change sb to identify a different object
sb = null; // change sb not to identify any object at all

在通常的说法中,这两者都将被描述为“变化”,因为人们会使用“”来引用变量(包含引用)和它所引用的对象(当它引用一个时)。这种松散是可以的,只要你在重要的时候记住这种区别。sbsb


答案 2

Immutable表示每次 和 对象的值发生更改时,都会在堆栈上为其创建一个新引用。在基元类型的情况下,你不能谈论不可变性,只有包装类是不可变的。Java不是通过引用来使用的。copy_by_value

如果您要传递基元变量或引用变量,则不会有任何区别,您始终传递变量中位的副本。因此,对于基元变量,您将传递表示值的位的副本,如果要传递对象引用变量,则将传递表示该引用的位的副本传递给对象。

例如,如果传递值为 3 的 int 变量,则传递的是表示 3 的位的副本。

一旦声明了基元,尽管它的值可以改变。its primitive type can never change