如果方法具有局部变量i
:
int i = 10;
然后我分配一个新值:
i = 11;
这会分配一个新的内存位置吗?或者只是替换原始值?
这是否意味着原语是不可变的?
答案 0 :(得分:58)
这会分配一个新的内存位置吗?或者只是替换原始值?
Java并没有真正保证变量对应于内存位置;例如,如果编译器可以看到你从未真正使用过它的值,或者它可以跟踪代码并直接使用适当的值。
但要把它放在一边。 。 。如果我们在这里采用抽象是局部变量表示调用堆栈上的内存位置,那么i
将只修改该内存位置的值。它不需要使用新的内存位置,因为变量i = 11
是引用旧位置的唯一内容。
这是否意味着原语是不可变的?
是和否:是的,原语是不可改变的,但不是,这不是因为上述原因。
当我们说某些东西是可变的时,我们的意思是它可以被改变:在具有相同身份的同时改变。例如,当你长出你的头发时,你正在改变自己:你仍然是你,但你的一个属性是不同的。
在原语的情况下,它们的所有属性完全取决于它们的身份; i
总是意味着1
,无论如何,1
总是1 + 1
。你无法改变它。
如果给定的2
变量的值为int
,则可以将其更改为值1
,但这是身份的完全更改:它不再具有相同的值以前的价值。这就像改变2
指向其他人而不是指向我:它实际上并没有改变 me ,只是改变了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
”,因为人们会使用“sb
”来引用变量(其中包含引用)和它引用的对象(当它引用一个时)。只要你记得重要的区别,这种松散就好了。
答案 1 :(得分:7)
Immutable
表示每次和对象的值发生更改时,都会在堆栈上为其创建新引用。
在原始类型的情况下,你不能谈论不变性,只有包装类是不可变的。
Java使用copy_by_value
而不是引用。
如果您传递原始变量或引用变量,那么没有区别 总是传递变量中的位副本。所以对于一个原始变量,你是 传递表示该值的位的副本,如果您传递的是对象引用变量,则表示您将对表示该对象的引用的位的副本传递给该对象。
例如,如果传递值为3的int变量,则传递代表3的位的副本。
一旦声明了基元its primitive type can never change
,它的值就会改变。
答案 2 :(得分:1)
这不是一个完整的答案,但它是一种证明原始类型值不变性的方法。
如果原始值(文字)是可变的,那么以下代码可以正常工作:
int i = 10; // assigned i the literal value of 10
5 = i; // reassign the value of 5 to equal 10
System.out.println(5); // prints 10
当然,这不是真的。
整数值(例如5,10和11)已存储在内存中。当您将变量设置为等于其中之一时:它会更改i
所在的内存插槽中的值。
您可以通过以下代码的字节码在此处看到:
public void test(){
int i = 10;
i = 11;
i = 10;
}
字节码:
// access flags 0x1
public test()V
L0
LINENUMBER 26 L0
BIPUSH 10 // retrieve literal value 10
ISTORE 1 // store it in value at stack 1: i
L1
LINENUMBER 27 L1
BIPUSH 11 // same, but for literal value 11
ISTORE 1
L2
LINENUMBER 28 L2
BIPUSH 10 // repeat of first set. Still references the same literal 10.
ISTORE 1
L3
LINENUMBER 29 L3
RETURN
L4
LOCALVARIABLE this LTest; L0 L4 0
LOCALVARIABLE i I L1 L4 1
MAXSTACK = 1
MAXLOCALS = 2
正如您在字节码中看到的那样(希望如此)它引用了文字值(例如:10),然后将其存储在变量i
的插槽中。当您更改i
的值时,您只是更改该插槽中存储的值。价值观本身并没有改变,它们的位置是。
答案 3 :(得分:0)
是的,它们是不可改变的。他们完全不可改变。
here中有一个很好的解释。它适用于Go,但在Java中也是如此。或C系列中的任何其他语言。
答案 4 :(得分:0)
原始文字和final
基本变量是不可变的。不是final
原始变量是可变的。
任何原始变量的标识都是该变量的名称,很明显,这样的标识是不可更改的。
答案 5 :(得分:0)
让我们更进一步,并在其中添加另一个变量j。
int i = 10;
int j = i;
i = 11
在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;
因此p1进行更改或p2进行更改将同时更改两者。无论是Java,Python还是Javascript都是相同的。在原始情况下,它是实际值,在对象情况下,它是实际对象的地址-这就是窍门。