几个特殊的例子
String str2 = new StringBuilder("计算机").append("技术").toString(); // 因为没有出现"计算机技术"字面量,只有“计算机”、“技术”,所以不会在常量池里生成"计算机技术",在池中没有,但是在 heap 中存在,则intern 时,会直接返回该 heap 中的引用。 System.out.println(str2 == str2.intern()); // true String str1=new StringBuilder("ja").append("va").toString(); // 这是因为java是关键字,在JVM初始化的相关类里肯定早就放进字符串常量池了。 System.out.println(str1 == str1.intern()); // false String s1=new String("test"); System.out.println(s1==s1.intern()); // true String s2=new StringBuilder("abc").toString(); // StringBuilder 的 toString 方法会 new String(),“abc”作为字面量是会放到常量池中的 System.out.println(s2==s2.intern()); // false
基本类型常量池
java 中基本类型的包装类的大部分都实现了常量池技术(严格来说应该叫对象池,在堆上),这些类是Byte, Short, Integer, Long, Character, Boolean, 另外两种浮点数类型的包装类则没有实现。另外 Byte, Short, Integer, Long, Character 这5种整型的包装类也只是在对应值小于等于127时才可使用对象池,也即对象不负责创建和管理大于127的这些类的对象。因为一般这种比较小的数用到的概率相对较大。
//5种整形的包装类Byte,Short,Integer,Long,Character的对象, //在值小于127时可以使用对象池 Integer i1 = 127; //这种调用底层实际是执行的Integer.valueOf(127),里面用到了IntegerCache对象池 Integer i2 = 127; System.out.println(i1 == i2); //输出true //值大于127时,不会从对象池中取对象 Integer i3 = 128; Integer i4 = 128; System.out.println(i3 == i4); //输出false //用new关键词新生成对象不会使用对象池 Integer i5 = new Integer(127); Integer i6 = new Integer(127); System.out.println(i5 == i6); //输出false //Boolean类也实现了对象池技术 Boolean bool1 = true; Boolean bool2 = true; System.out.println(bool1 == bool2); //输出true //浮点类型的包装类没有实现对象池技术 Double d1 = 1.0; Double d2 = 1.0;
Integer.java 部分源码
// valueOf 方法 public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); } // IntegerCache 实现 private static class IntegerCache { static final int low = -128; static final int high; static final Integer cache[]; // static 块中预先缓存 -128 ~ 127 这些数据,Long 同理 static { // high value may be configured by property int 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_VALUE h = 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() {} }
参考资料
- 《深入理解 Java 虚拟机》 第三版 周志明
- 《Java 虚拟机规范(Java SE 8 版)》 爱飞翔 周志明 等译
- JVM深入解析三之常量池 CSDN 向上奔跑