【问题标题】:Are Java primitives immutable?Java原语是不可变的吗?
【发布时间】:2013-08-03 20:38:42
【问题描述】:

如果一个方法有一个局部变量i

int i = 10;

然后我分配一个新值:

i = 11;

这会分配一个新的内存位置吗?还是直接替换原来的值?

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

【问题讨论】:

  • 它将替换原来的。 Java 原语不是对象。 Integer(和其他原始包装类)不可变的。
  • @BrianRoach 不,他没有。根据您的逻辑,字符串是可变的:String str = "test"; str = "newStr";。要回答 OP 的问题,它们实际上是不可变的。如果你考虑i++,那真的是:i = i + 1。您可以看到它采用 i 的值,加一并将 i 重新分配给这个新值。
  • 对不起,你们现在把我弄糊涂了.....
  • 我实际上并不认为这是一个坏问题……不知道为什么会有这么多反对票。
  • @BrianRoach 我也一直在研究ballmer curve

标签: java primitive


【解决方案1】:

这会分配一个新的内存位置吗?还是直接替换原来的值?

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

通俗地说,这两个都将被描述为“更改sb”,因为人们将使用“sb”来引用变量(其中包含一个引用)和它引用的 object(当它引用一个时)。这种松散是可以的,只要你记住重要的区别。

【讨论】:

    【解决方案2】:

    Immutable 表示每次和对象的值发生变化时,都会在堆栈上为其创建一个新的引用。 对于原始类型,您不能谈论不可变性,只有包装类是不可变的。 Java 不通过引用使用copy_by_value

    传递原始变量或引用变量没有区别,你是 总是传递变量中位的副本。所以对于一个原始变量,你是 传递表示值的位的副本,如果您传递的是对象引用变量,则传递的是表示对对象的引用的位的副本。

    例如,如果你传递一个值为 3 的 int 变量,你传递的是代表 3 的位的副本。

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

    【讨论】:

    • @Maroun Maroun 我刚刚尝试了以下方法:int i = 10;诠释 j = 我;系统(一); // 10 系统 (j); // 10 i = 11; syso(i) // 11 syso(j) // 10 那么如果i没有在内存中新建一个地方,那么j的值怎么可能一样呢?
    • 在原始类型的情况下,当您将 i 的值分配给 j 时,与 i 的值对应的位被复制,您没有分配 i 的引用,因为您不能谈论引用在原始类型的情况下。
    【解决方案3】:

    让我们更进一步,在其中添加另一个变量 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,都是一样的。在原始的情况下,它是实际值,但在对象的情况下,它是实际对象的地址 - 这就是诀窍。

    【讨论】:

      【解决方案4】:

      这不是一个完整的答案,但它是一种证明原始类型值不变性的方法。

      如果原始值(文字)是可变的,那么下面的代码可以正常工作:

      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 的值时,您只是更改了存储在该插槽中的值。值本身并没有改变,它们的位置是。

      【讨论】:

        【解决方案5】:

        是的,它们是不可变的。它们是完全不变的。

        here 中有一个很好的解释。它适用于 Go,但在 Java 中也是如此。或 C 系列中的任何其他语言。

        【讨论】:

        • 不,不是。原语是不可变的,变量不是。
        【解决方案6】:

        原始文字和final 原始变量是不可变的。不是final 原始变量是可变的。

        任何原始变量的标识都是该变量的名称,很明显,这样的标识是不可更改的。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-06
          • 2013-08-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多