文章目录
- Class常量池
- 运行时常量池
- String常量池
- 基本类型常量池
- Integer 常量池
- Long 常量池
- 加餐部分
Class常量池
每个Class字节码文件中包含类常量池用来存放字面量以及符号引用等信息。
运行时常量池
java文件被编译成class文件之后,也就是会生成我上面所说的 class常量池,那么运行时常量池又是什么时候产生的呢?
jvm在执行某个类的时候,必须经过加载、连接、初始化,而连接又包括验证、准备、解析三个阶段。而当类加载到内存中后,jvm就会将 class常量池 中的内容存放到 运行时常量池 中。
在上面我也说了,class常量池 中存的是字面量和符号引用,也就是说他们存的并不是对象的实例,而是对象的符号引用值。而经过解析(resolve)之后,也就是把符号引用替换为直接引用。
运行时常量池区域是在方法区中。
String常量池
在JDK1.7后String常量池的所在区域被挪至堆内存中,原位置是在运行时常量池中,而在JDK1.7后JDK在堆内开辟了一块空间用作了String常量池。
String name="zhangsan";
String nameTwo=new String("lisi");
上述两行代码中“zhangsan”字面量是存储在String常量池中,而“lisi”则是在String常量池以及堆中各有一份,使用nameTwo时获取lisi时也是从堆中获取。
基本类型常量池
基本类型的常量池更偏向于缓存的概念,每个基本类型的包装类都有对应的内部缓存类,若发现所需数据已完成缓存则直接从缓存对象的cache数组中获取。整数、字符类型的最大缓存值为127而最小缓存值为-128,浮点型没有缓存。
private static class IntegerCache {static final int low = -128;static final int high;static final Integer cache[];static {// high value may be configured by propertyint h = 127;String integerCacheHighPropValue =sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");if (integerCacheHighPropValue != null) {try {int i = parseInt(integerCacheHighPropValue);i = Math.max(i, 127);// Maximum array size is Integer.MAX_VALUEh = Math.min(i, Integer.MAX_VALUE - (-low) -1);} catch( NumberFormatException nfe) {// If the property cannot be parsed into an int, ignore it.}}high = h;cache = new Integer[(high - low) + 1];int j = low;for(int k = 0; k < cache.length; k++)cache[k] = new Integer(j++);// range [-128, 127] must be interned (JLS7 5.1.7)assert IntegerCache.high >= 127;}private IntegerCache() {}}
Integer 常量池
当发现所需的值小于最小缓存值并且大于最大缓存值后,则直接创建新的对象
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)return IntegerCache.cache[i + (-IntegerCache.low)];return new Integer(i);}
Long 常量池
当发现所需的值小于最小缓存值并且大于最大缓存值后,则直接创建新的对象
public static Long valueOf(long l) {final int offset = 128;if (l >= -128 && l <= 127) { // will cachereturn LongCache.cache[(int)l + offset];}return new Long(l);}
加餐部分
String intern方法
String hello=new String("he")+new String("llo");String helloTwo=hello.intern();System.out.println(helloTwo==hello);
JDK1.6
JDK1.6intern方法:变量hello调用intern方法,首先会去String常量池中找是否有hello这个常量,当发现未找到时则把堆中的hello对象的“hello”复制到String常量池,若发现String常量池中有“hello”时则会将常量池中的“hello”返回给helloTwo。
如上图所示在JDK1.6的时候intern方法在调用后,发现未找到时则把堆中的hello对象的“hello”复制到String常量池。
JDK1.7
JDK1.7 intern方法:变量hello调用intern方法,首先会去String常量池中找是否有hello这个常量,当发现未找到时则把堆中的hello对象地址值存入到String常量池,若发现String常量池中有“hello”时则会将常量池中的“hello”返回给helloTwo。