java - 不可变类的存储区域

标签 java immutability

在最近的采访中,我被问到字符串是否存储在字符串池中,因为它支持不变性,那么我们自定义的不可变类存储在java中的哪里。

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

但面试官一直争论说—— 如果 String 有字符串池,那么不可变类也可以有类似的概念吗?

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

最佳答案

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因为“堆是运行时数据区域,所有类实例和数组的内存都从这里分配。

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

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

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

例如,许多包装类都具有此类共享,ShortIntegerLongvalueOf 方法code> 将返回 -128 … +127 范围内的值的共享实例,并且允许实现共享更多实例,而 ByteBoolean返回所有可能值的共享实例。

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

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

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

关于java - 不可变类的存储区域,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58088972/

相关文章:

java - Thymeleaf 以一种形式提交多个提交按钮

java - 如何在Webots中显示图表?

java - STS 和 org.eclipse.jdi.TimeoutException 中的远程调试

c# - 对于 var q = "A"+ "B"+ "C",字符串连接在 C# 中是如何发生的

arrays - 如果 Scala 中需要不可变数组,返回 IndexesSeq 而不是 Array 是否正确?

reference - 为什么我可以将不可变引用传递给 BufReader,而不是可变引用?

java - 错误 "cannot resolve method"

java - 使用 javamail 通过 Swing 查看电子邮件

c# - 在不可变对象(immutable对象)上创建一个 "with"方法

javascript - 在 Immutable.js 中解析嵌套记录