Java原语是不可变的吗?

时间:2013-08-03 20:38:42

标签: java primitive

如果方法具有局部变量i

int i = 10;

然后我分配一个新值:

i = 11;

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

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

6 个答案:

答案 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。

enter image description here

对于对象,值(或引用)本身就是一个地址(或堆地址),因此,如果其中一个更改,它也将对其他对象反映。例如在对象中:-

Person p1 = new Person();
Person p2 = p1;

enter image description here

因此p1进行更改或p2进行更改将同时更改两者。无论是Java,Python还是Javascript都是相同的。在原始情况下,它是实际值,在对象情况下,它是实际对象的地址-这就是窍门。