简体   繁体   English

幕后的Java不可变性

[英]Java Immutability behind the scenes

So, I'm new to Java and am trying to get my head around how immutable objects are implemented, and why they can appear to be mutable nonetheless. 所以,我是Java的新手,我正试图了解如何实现不可变对象,以及为什么它们看起来仍然是可变的。 A lot of the sources I've looked at seem to 'suggest' what goes on under the hood, but I'd just like clarification as to whether I'm on the right track. 我看过的许多消息来源似乎都在暗示“幕后发生了什么”,但我想澄清一下我是否走在正确的轨道上。

Using the following trivial example: 使用以下简单示例:

import java.math.*;

class BIMutability {

   public static void main(String args[]) {

      BigInteger biValue = new BigInteger("2");

      for (int i=1; i<10; i++) {
         System.out.println(i + ". biValue = " + biValue);
         biValue = biValue.multiply(biValue);
      }
   }
}

which, when run, produces: 在运行时产生:

1. biValue = 2
2. biValue = 4
3. biValue = 16
4. biValue = 256
5. biValue = 65536
6. biValue = 4294967296
7. biValue = 18446744073709551616
8. biValue = 340282366920938463463374607431768211456
9. biValue = 115792089237316195423570985008687907853269984665640564039457584007913129639936

On the surface, it would appear that biValue is, in fact, mutable after all. 从表面上看,似乎biValue实际上是可变的。 I know that that's not the case. 我知道情况并非如此。

My understanding is thus: biValue is essentially a pointer variable. 因此我的理解是: biValue本质上是一个指针变量。 Upon instantiation at runtime, heap is allocated for an object of class BigInteger, its constructor is called which (among other things) initializes the object's value according to the literal value "2", and biValue is finally assigned a pointer to the object space. 在运行时实例化时,为类BigInteger的对象分配堆,调用其构造函数(其中包括)根据文字值“2”初始化对象的值,最后为biValue分配指向对象空间的指针。 (Is this correct?) (它是否正确?)

Subsequently, on each successive iteration of the loop, the multiply method allocates additional heap for a new object instantiation to contain the resulting immutable value (eg heap for the result of the 4th iteration is allocated and the new object assigned the value 256) and biValue is assigned a pointer which references the new object. 随后,在循环的每次连续迭代中, 乘法方法为新对象实例化分配额外的堆以包含所得到的不可变值(例如,分配第4次迭代的结果的堆,并且新对象分配值256)和biValue被赋予一个引用新对象的指针。 (Is this also correct?) (这也是正确的吗?)

(As an aside, from what I gather then, the previous objects' heap space are just orphaned? Or is garbage collection performed right away? If not, it just seems like you could quickly run out of heap under certain circumstances.) (顺便说一句,从我收集的内容来看,之前的对象的堆空间只是孤立的?或者是否立即执行垃圾收集?如果不是,那么在某些情况下,您似乎很快就会用尽堆。)

So am I seeing this correctly, or am I missing important details, or...? 我是否正确地看到了这一点,或者我错过了重要的细节,还是......?

Thanks! 谢谢!

You are right about how multiply creates a new BigInteger object each time you call it, and that biValue 's value changes in each iteration. 你说得对有关如何multiply创建一个新BigInteger每次调用时对象,而且biValue在每个迭代的价值变化。

When we say immutability, we mean that objects can't be mutated, not variables . 当我们说不变性时,我们的意思是对象不能变异,而不是变量 A variable that can't be mutated can be declared using the final modifier. 可以使用final修饰符声明无法变异的变量。

And yes, many immutable classes might "seem" to be mutable. 是的,许多不可变类可能“看起来”是可变的。 In such cases, the seemingly mutating methods will create a new object. 在这种情况下,看似变异的方法将创建一个新对象。

Regarding the fate of the BigInteger objects in the previous iterations of the loop, yes they will be garbage collected. 关于循环的前一次迭代中BigInteger对象的命运,是的,它们将被垃圾收集。 However, the time that this happens is non-deterministic. 但是,发生这种情况的时间是不确定的。 Note that it probably will fill up the heap not because GC didn't collect the unused objects, but because the number is too big. 请注意,它可能填满堆不是因为GC没有收集未使用的对象,而是因为数量太大。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM