JVM 三种常量池(下)

简介: 本文主要讲述三种常量池: Class 常量池、字符串常量池、还有基本类型常量池。 默认 jdk 版本:jdk 1.8

几个特殊的例子


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() {}
}


参考资料


  1. Oracle Jdk 文档


  1. 《深入理解 Java 虚拟机》 第三版 周志明


  1. 《Java 虚拟机规范(Java SE 8 版)》 爱飞翔 周志明 等译


  1. JVM深入解析三之常量池 CSDN 向上奔跑


相关文章
|
7月前
|
存储 Java 编译器
【面试题精讲】JVM-方法区-运行时常量池
【面试题精讲】JVM-方法区-运行时常量池
|
11月前
|
Java 编译器 C++
JVM 常量池
JVM 常量池
|
12月前
|
Java
JVM - Class常量池 || 运行时常量池
JVM - Class常量池 || 运行时常量池
60 0
|
存储 Java 关系型数据库
【底层原理之旅—攻克你的技术盲点之JVM常量池】|Java 刷题打卡
【底层原理之旅—攻克你的技术盲点之JVM常量池】|Java 刷题打卡
116 0
【底层原理之旅—攻克你的技术盲点之JVM常量池】|Java 刷题打卡
|
Oracle Java 关系型数据库
JVM虚拟机-Class文件之常量池
JVM虚拟机-Class文件之常量池
141 0
JVM虚拟机-Class文件之常量池
|
存储 Java 编译器
JVM 三种常量池(中)
本文主要讲述三种常量池: Class 常量池、字符串常量池、还有基本类型常量池。 默认 jdk 版本:jdk 1.8
178 0
JVM 三种常量池(中)
|
Java
JVM 三种常量池(上)
本文主要讲述三种常量池: Class 常量池、字符串常量池、还有基本类型常量池。 默认 jdk 版本:jdk 1.8
99 0
|
索引
JVM14_Class文件结构细节、魔数、Class文件版本、常量池、访问标识(或标志)、类索引|父类索引|接口索引集合、字段|方法|属性表集合(七)
⑩. IDEA中集成jclasslib说明Class文件信息 ①. Class文件详解 ②. 方法表集合 ③. code属性 ④. LineNumberTable、LocalVariableTable ④. SourceFile属性
JVM14_Class文件结构细节、魔数、Class文件版本、常量池、访问标识(或标志)、类索引|父类索引|接口索引集合、字段|方法|属性表集合(七)