Java 原语是不可变的吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18037082/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 21:58:16  来源:igfitidea点击:

Are Java primitives immutable?

javaprimitive

提问by fYre

If a method has a local variable i:

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

int i = 10;

and then I assign a new value:

然后我分配一个新值:

i = 11;

Will this allocate a new memory location? Or just replace the original value?

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

Does this mean that primitives are immutable?

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

采纳答案by ruakh

Will this allocate a new memory location? Or just replace the original value?

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

Java does not really make any guarantees that variables will correspond to memory locations; for example, your method might be optimized in such a way that iis stored in a register — or might not even be stored at all, if the compiler can see that you never actually use its value, or if it can trace through the code and use the appropriate values directly.

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

But setting that aside . . . if we take the abstraction here to be that a local variable denotes a memory location on the call stack, then i = 11will simply modify the value at that memory location. It will not need to use a new memory location, because the variable iwas the only thing referring to the old location.

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

Does this mean that primitives are immutable?

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

Yes and no: yes, primitives are immutable, but no, that's not because of the above.

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

When we say that something is mutable, we mean that it can be mutated: changed while still having the same identity. For example, when you grow out your hair, you are mutating yourself: you're still you, but one of your attributes is different.

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

In the case of primitives, all of their attributes are fully determined by their identity; 1always means 1, no matter what, and 1 + 1is always 2. You can't change that.

对于基元,它们的所有属性都完全由它们的身份决定;1总是意味着1,无论如何,并且1 + 1总是2。你不能改变这一点。

If a given intvariable has the value 1, you can change it to have the value 2instead, but that's a total change of identity: it no longer has the same value it had before. That's like changing meto point to someone else instead of to me: it doesn't actually change me, it just changes me.

如果给定的int变量具有 value 1,您可以将其更改为具有该值2,但这完全改变了身份:它不再具有与以前相同的值。这就像改变me指向其他人而不是指向我:它实际上并没有改变,它只是改变了me

With objects, of course, you can often do both:

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

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

In common parlance, both of these will be described as "changing sb", because people will use "sb" both to refer the variable(which contains a reference) and to the objectthat it refers to (when it refers to one). This sort of looseness is fine, as long as you remember the distinction when it matters.

通俗地说,这两者都将被描述为“改变sb”,因为人们将使用“ sb”来指代变量(包含引用)和它所指的对象(当它指代一个时)。这种松散很好,只要你在重要的时候记住区别。

回答by Java Panter

Immutablemeans that each time the value of and object has changed a new reference is created for it on stack. You can't talk about immutability in case of primitive types,only the Wrapper Classes are immutable. Java uses copy_by_valuenot by reference.

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

It makes no difference if you're passing primitive or reference variables, you are always passing a copy of the bits in the variable. So for a primitive variable, you're passing a copy of the bits representing the value and if you're passing an object reference variable, you're passing a copy of the bits representing the reference to an object.

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

For example, if you pass an int variable with the value of 3, you're passing a copy of the bits representing 3.

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

Once a primitive has been declared, its primitive type can never change, although its value can change.

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

回答by nes1983

Yes, they are immutable. They're totally unchangeable.

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

There's a nice explanation buried in here. It's for Go, but it's the same thing in Java. Or any other language in the C family.

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

回答by ruakh

This isn't a full answer, but it is a way to prove the immutability of primitive-type values.

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

If primitive values (literals) are mutable, then the following code would work fine:

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

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

Of course, this isn't true.

当然,这不是真的。

The integer values, such as 5, 10 and 11 are already stored in the memory. When you set a variable equal to one of them: it changes the value in the memory-slot where iis.

整数值,例如 5、10 和 11,已经存储在内存中。当您将变量设置为等于其中之一时:它会更改内存插槽中的i值。

You can see this here through the bytecode for the following code:

您可以在此处通过以下代码的字节码看到这一点:

public void test(){
    int i = 10;
    i = 11;
    i = 10;
}

Bytecode:

字节码:

// 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

As you can see in the bytecode (hopefully) it references the literal value (example: 10) and then stores it in the slot for variable i. When you change the value of i, you are just changing which value is stored in that slot. The values themselves aren't changing, the location of them is.

正如您在字节码中所看到的(希望如此),它引用了文字值(例如:10),然后将其存储在变量的插槽中i。当您更改 的值时i,您只是在更改存储在该插槽中的值。值本身没有改变,它们的位置是。

回答by Rostislav Krasny

Primitive literals and finalprimitive variables are immutable. Not finalprimitive variables are mutable.

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

Identity of any primitive variable is the name of that variable and it's obvious that such an identity is unchangeable.

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

回答by Goyal Vicky

Let's take a step further and add another variable j in it.

让我们更进一步,在其中添加另一个变量 j。

int i = 10;
int j = i;
i = 11

In java 8 byte of memory is allocated for value of i and j (4 byte for i and 4 byte for j). The value of i is passed to j and now j and i have same value but different memory address. Now value of i is changed to 11 meaning for same memory address the value of i is changed from 10 to 11 but value of j is in different memory location and so it remains as 10.

在 java 中,为 i 和 j 的值分配了 8 字节的内存(i 为 4 字节,j 为 4 字节)。i 的值传递给 j,现在 j 和 i 具有相同的值但不同的内存地址。现在 i 的值更改为 11,这意味着对于相同的内存地址,i 的值从 10 更改为 11,但 j 的值位于不同的内存位置,因此它保持为 10。

enter image description here

在此处输入图片说明

In case of objects the value(or reference) itself is an address(or heap address) so if one changes it, it will be reflected for others as well. For example in objects :-

在对象的情况下,值(或引用)本身是一个地址(或堆地址),所以如果一个人改变了它,它也会反映给其他人。例如在对象中:-

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

enter image description here

在此处输入图片说明

So either p1 make changes or p2 make changes it will be changed for both. Whether it is Java, Python or Javascript it is same. In case of primitive it is the actual value but in case of objects it is a address of actual object - that's the trick.

因此,无论是 p1 进行更改还是 p2 进行更改,两者都会更改。无论是 Java、Python 还是 Javascript,它都是一样的。在原始值的情况下,它是实际值,但在对象的情况下,它是实际对象的地址 - 这就是技巧。