我的问题是关于java实习和常数池.
Java维护一个常量池java.lang.String
,巧妙地使用JVM内存,并且这样做java.lang.String是不可变的.那么为什么java不维护其他不可变类型的常量池,例如Long,Integer,Char,Short?那会不会节省内存呢?
我知道整数被汇集到值范围[-127,127],尽管我不明白选择这个范围的原因.
这是我编写的测试代码,用于测试其他不可变数据类型的池.
public class PoolTest { public static void main(String... args) { // Pooling of Integer [-127, 127] Integer x = 127, y = 127; System.out.println("Integer:" + (x == y)); // prints true x = 129; y = 129; System.out.println("Integer:" + (x == y)); // prints false // Apparent pooling of short [-127, 127] Short i = 127, j = 127; System.out.println("Short: " + (i == j)); // prints true i = 128; j = 128; System.out.println("Short: " + (i == j)); // prints false // No pooling of long values Long k = 10L, l = 10L; System.out.println("Long: " + (i == j)); // prints false k = 128L; l = 128L; System.out.println("Long: " + (i == j)); // prints false } }
chrylis -on .. 8
常量池的目的是通过保留多个常量副本来减少所需的内存开销.在String
s 的情况下,JVM本身就需要为每个可单独区分的常量保留一些对象,而Java规范基本上说JVM应该String
在类加载时重复删除对象.通过手动将String
s 放置在池中的能力intern
很低,并且允许程序员识别将在程序生命周期中出现的特定值(例如属性)并告诉JVM将它们放在正常垃圾的路上采集.
另一方面,汇集数字常量并没有多大意义,原因如下:
大多数特定数字都不会在给定程序的代码中使用.
当在代码中使用数字时,将它们作为立即操作码值嵌入代码中在内存方面比试图汇集它们更便宜.请注意,即使是空的,也有空String
的char[]
,一个int
是长度,另一个是它的长度hashCode
.相反,对于数字,最多需要八个立即字节.
作为最新的Java版本,Byte
,Short
,和Integer
从对象-128到127(0到127 Character
)的预缓存性能方面的原因,不能以节省内存.大概选择此范围是因为这是有符号字节的范围,并且它将涵盖大量常见用途,而尝试预先处理大量值是不切实际的.
需要注意的是,请记住,在Java 5中引入自动装箱和泛型类型之前很久就已经制定了关于实习的规则,这大大扩展了随机使用的包装类的数量.使用量的增加导致Sun将这些常见值添加到常量池中.
常量池的目的是通过保留多个常量副本来减少所需的内存开销.在String
s 的情况下,JVM本身就需要为每个可单独区分的常量保留一些对象,而Java规范基本上说JVM应该String
在类加载时重复删除对象.通过手动将String
s 放置在池中的能力intern
很低,并且允许程序员识别将在程序生命周期中出现的特定值(例如属性)并告诉JVM将它们放在正常垃圾的路上采集.
另一方面,汇集数字常量并没有多大意义,原因如下:
大多数特定数字都不会在给定程序的代码中使用.
当在代码中使用数字时,将它们作为立即操作码值嵌入代码中在内存方面比试图汇集它们更便宜.请注意,即使是空的,也有空String
的char[]
,一个int
是长度,另一个是它的长度hashCode
.相反,对于数字,最多需要八个立即字节.
作为最新的Java版本,Byte
,Short
,和Integer
从对象-128到127(0到127 Character
)的预缓存性能方面的原因,不能以节省内存.大概选择此范围是因为这是有符号字节的范围,并且它将涵盖大量常见用途,而尝试预先处理大量值是不切实际的.
需要注意的是,请记住,在Java 5中引入自动装箱和泛型类型之前很久就已经制定了关于实习的规则,这大大扩展了随机使用的包装类的数量.使用量的增加导致Sun将这些常见值添加到常量池中.