如果方法有局部变量i
:
int i = 10;
Run Code Online (Sandbox Code Playgroud)
然后我分配一个新值:
i = 11;
Run Code Online (Sandbox Code Playgroud)
这会分配一个新的内存位置吗?或者只是替换原始值?
这是否意味着原语是不可变的?
rua*_*akh 61
这会分配一个新的内存位置吗?或者只是替换原始值?
Java并没有真正保证变量对应于内存位置; 例如,您的方法可能会以i
存储在寄存器中的方式进行优化- 或者甚至可能根本不存储,如果编译器可以看到您实际上从未使用过它的值,或者它是否可以跟踪代码和直接使用适当的值.
但把它放在一边...如果我们在这里采用抽象是局部变量表示调用堆栈上的内存位置,那么i = 11
将简单地修改该内存位置的值.它不需要使用新的内存位置,因为变量i
是唯一引用旧位置的东西.
这是否意味着原语是不可变的?
是和否:是的,原语是不可改变的,但不是,这不是因为上述原因.
当我们说某些东西是可变的时,我们的意思是它可以被改变:改变,同时仍具有相同的身份.例如,当你长出你的头发时,你正在改变自己:你仍然是你,但你的一个属性是不同的.
在原语的情况下,它们的所有属性完全由它们的身份决定; 1
总是意味着1
,无论如何,1 + 1
总是如此2
.你不能改变它.
如果给定int
变量具有该值1
,则可以将其更改为具有该值2
,但这是身份的完全更改:它不再具有与之前相同的值.这就像改变me
指向别人而不是指向我:它实际上并没有改变我,只是改变了me
.
当然,对于对象,您通常可以同时执行以下操作:
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
Run Code Online (Sandbox Code Playgroud)
按照通常的说法,这两者都将被描述为"改变sb
",因为人们将使用" sb
"来引用变量(包含引用)和引用它的对象(当它引用一个时).这种松散是好的,只要你记住重要的区别.
Immutable
表示每次和对象的值发生更改时,都会在堆栈上为其创建新引用.在原始类型的情况下,你不能谈论不变性,只有包装类是不可变的.Java copy_by_value
不是通过引用使用.
如果您传递原始变量或引用变量没有区别,那么您总是传递变量中的位副本.因此,对于原始变量,您传递的是表示值的位的副本,如果您传递的是对象引用变量,则会将表示对该对象的引用的位的副本传递给对象.
例如,如果传递值为3的int变量,则传递代表3的位的副本.
一旦声明了一个原语its primitive type can never change
,它的值就会改变.
让我们更进一步,在其中添加另一个变量 j。
int i = 10;
int j = i;
i = 11
Run Code Online (Sandbox Code Playgroud)
在 java 中,为 i 和 j 的值分配了 8 字节的内存(i 为 4 字节,j 为 4 字节)。i 的值传递给 j,现在 j 和 i 具有相同的值但不同的内存地址。现在 i 的值更改为 11,这意味着对于相同的内存地址,i 的值从 10 更改为 11,但 j 的值位于不同的内存位置,因此它保持为 10。
在对象的情况下,值(或引用)本身是一个地址(或堆地址),所以如果一个人改变了它,它也会反映给其他人。例如在对象中:-
Person p1 = new Person();
Person p2 = p1;
Run Code Online (Sandbox Code Playgroud)
因此,无论是 p1 进行更改还是 p2 进行更改,两者都会更改。无论是 Java、Python 还是 Javascript,它都是一样的。在原始值的情况下,它是实际值,但在对象的情况下,它是实际对象的地址 - 这就是技巧。