不可变存储区类

Stored area of immutable classes

在最近的采访中,有人问我字符串是否存储在字符串池中,因为它支持不变性,那么我们自定义的不可变 classes 存储在 java.[=11= 中的哪里]

我已经给出了以下解释 - 所有 class 变量基元或对象引用(它只是指向对象存储位置的指针,即堆)也存储在堆中。 类由class-loader加载,静态变量和静态对象引用存储在堆中的一个特殊位置,永久代。

但是面试官一直在争辩说—— 如果 String 有字符串池,不可变 class 是否也有类似的概念?

谁能解释一下不可变 classes 的存储区域,因为它们也像字符串一样不可变?

In recent interview, I was asked if string is stored in string-pool, as it supports immutability then where are our custom immutable classes are stored in java.

这是一个前提错误的无意义问题。字符串不是“存储在字符串池中”,它们像任何其他对象一样存储在堆中。这是一种重言式,因为堆内存 is precisely defined as “堆是 运行 时间数据区域,所有 class 实例和数组的内存都是从中分配的.

字符串池可以看作包含字符串,就像一个Collection可能包含对象一样,但无论哪种情况,它都只是持有对对象的引用。因此,根据定义,池中包含的字符串仍存储在堆内存中,而池具有对它的引用。

But the interviewer kept arguing that - If String has string-pool, can immutable classes also have some concept like that?

这是一个完全不同的问题。当然,您可以实现对象池,如上面的 Collection 类比所示。就像池中包含的字符串仍然存储在堆内存中一样,当池中使用的任何数据结构引用它们时,class 的对象仍然存储在堆内存中。对象是不可变的甚至没有必要有这样一个池,但是当可能发生变化时,隐含的实例共享会导致语义问题。所以创建池通常只对不可变对象有意义。

例如,很多包装器 classes 都有这样的共享,ShortIntegerLongvalueOf 方法将 [= -128 … +127 范围内值的 50=] 共享实例和实现允许共享更多实例,而 ByteBoolean return 共享所有可能值的实例。

但是,并非每个不可变 class 都为其所有值实现一个池是有原因的:

  • 如果有一个很大的值space,你必须考虑支持未使用对象的垃圾回收,即使被池引用
  • 你必须考虑你的池的线程安全
  • 以上两点可能会导致复杂的解决方案,当对象仅短时间使用时您不想支付性能损失,因为共享只会减少长寿命对象的内存消耗

这也适用于现有示例。包装器对象仅提供有限值 space 的共享对象。哪些是预分配的,从不进行 GC。另一方面,字符串池是动态的、线程安全的并且支持对其元素进行垃圾回收,这就是为什么 intern() 不是一个廉价操作并且不应应用于每个字符串的原因。相反,池主要用于常量,这些常量确实是长期存在的。