请选择 进入手机版 | 继续访问电脑版

[java] Java常量池详解

[复制链接]
查看112 | 回复6 | 2021-9-12 20:10:39 | 显示全部楼层 |阅读模式
目次

java中有几种不同的常量池,以下的内容是对java中几种常量池的先容 ,此中 最常见的就是字符串常量池。

(1)class常量池

在Java中,Java类被编译后就会形成一份class文件;class文件中除了包含类的版本、字段、方法、接口等形貌 信息外,还有一项信息就是常量池,用于存放编译器天生 的各种字面量和符号引用,每个class文件都有一个class常量池。

此中 字面量包括:1.文本字符串 2.八种基本范例 的值 3.被声明为final的常量等;

符号引用包括:1.类和方法的全限定名 2.字段的名称和形貌 符 3.方法的名称和形貌 符。

(2)运行时常量池

运行时常量池存在于内存中,也就是class常量池被加载到内存之后的版本,是方法区的一部分(JDK1.8 运行时常量池在元空间,元空间也是方法区的一种实现)。不同之处是:它的字面量可以动态的添加(String类的intern()),符号引用可以被剖析 为直接引用。

JVM在实行 某个类的时间 ,必须颠末 加载、毗连 、初始化,而毗连 又包括验证、预备 、剖析 三个阶段。而当类加载到内存中后,jvm就会将class常量池中的内容存放到运行时常量池中,这里所说的常量包括:基本范例 包装类(包装类不管理浮点型,整形只会管理-128到127)和字符串范例 (即通过String.intern()方法可以逼迫 将String放入常量池),运行时常量池是每个类私有的。在剖析 阶段,会把符号引用更换 为直接引用。

(3)基本范例 包装类常量池

Java 基本范例 的包装类的大部分都实现了常量池技术。Byte,Short,Integer,Long这 4 种包装类默认创建了数值 [-128,127] 的相应范例 的缓存数据,Character创建了数值在[0,127]范围的缓存数据,Boolean直接返回True或False,假如 超出对应范围就会去创建新的对象。两种浮点数范例 的包装类Float,Double并没有实现常量池技术。

Integer 缓存源码:

  1. /**
  2. *此方法将始终缓存-128 到 127(包括端点)范围内的值,并可以缓存此范围之外的其他值。
  3. */
  4. public static Integer valueOf(int i) {
  5. if (i >= IntegerCache.low && i <= IntegerCache.high)
  6. return IntegerCache.cache[i + (-IntegerCache.low)];
  7. return new Integer(i);
  8. }
  9. private static class IntegerCache {
  10. static final int low = -128;
  11. static final int high;
  12. static final Integer cache[];
  13. }
复制代码

举个栗子:

  1. Integer i1 = 40;
  2. Integer i2 = 40;
  3. Integer i3 = 0;
  4. Integer i4 = new Integer(40);
  5. Integer i5 = new Integer(40);
  6. Integer i6 = new Integer(0);
  7. System.out.println("i1=i2 " + (i1 == i2));
  8. System.out.println("i1=i2+i3 " + (i1 == i2 + i3));
  9. System.out.println("i1=i4 " + (i1 == i4));
  10. System.out.println("i4=i5 " + (i4 == i5));
  11. System.out.println("i4=i5+i6 " + (i4 == i5 + i6));
  12. System.out.println("40=i5+i6 " + (40 == i5 + i6));
复制代码

效果 :

  1. i1=i2         true
  2. i1=i2+i3   true
  3. i1=i4        false
  4. i4=i5        false
  5. i4=i5+i6   true
  6. 40=i5+i6   true
复制代码

表明 :1-4语句效果 应该很显然,由于 Integer i1=40 这一行代码会发生装箱,也就是说这行代码等价于 Integer i1=Integer.valueOf(40),Integer.valueOf()方法基于减少对象创建次数和节流 内存的思量 ,缓存了[-128,127]之间的数字,假如 在此数字范围内直接返回缓存中的对象。在此之外,直接new出来,显然40在常量池的缓存[-128,127]范围内;因此,i1 直接利用 的是常量池中的对象。而Integer i1 = new Integer(40) 会直接创建新的对象;语句 i4 == i5 + i6,由于 +这个操作符不实用 于 Integer 对象,起首 i5 和 i6 举行 主动 拆箱操作,举行 数值相加,即 i4 == 40。然后 Integer 对象无法与数值举行 直接比较,以是 i4 主动 拆箱转为 int 值 40,终极 这条语句转为 40 == 40 举行 数值比较,以是 效果 为true。第六条语句同理。

额外阐明 :全部 整型包装类对象之间值的比较,全部利用 equals 方法比较。

对于Integer var = ?在-128至127之间的赋值,Integer对象是在 IntegerCache.cache产生,会复用已有对象,这个区间内的Integer值可以直接利用 ==举行 判定 ,但是这个区间之外的全部 数据,都会在堆上产生,并不会复用已有对象,保举 利用 equals方法举行 判定 。

(4)字符串常量池

在JDK1.6及之前版本,字符串常量池存放在方法区中的,在JDK1.7版本以后,字符串常量池被移到了堆中了。

HotSpot VM里,记录interned string的一个全局表叫做StringTable,它本质上就是个HashSet;这个StringTable在每个HotSpot VM的实例只有一份,被全部 的类共享。

留意 :它只存储对java.lang.String实例的引用,而不存储String对象的内容

字符串常量池和上面的基本范例 包装类常量池有些不同,字符串常量池中没有事先缓存一些数据,而是假如 要创建的字符串在常量池内存在就返回对象的引用,假如 不存在就创建一个放在常量池中;

在Java中,有两种创建字符串对象的方法,一种是字面量直接创建,另一种是new一个String对象,这两种方法创建字符串对象的过程会不一样;

  1. (1)String str = "abc";
  2. (2)String str = new String("abc");
复制代码

假如 是第一种方式创建对象,由于 是字面量直接创建,以是 在编译的时间 是确定的,假如 该字符串不在常量池中会将该字符串放入常量池中并返回字符串对象的引用,假如 在常量池中直接返回字符串对象的引用,假如 是第二种方式创建对象,由于 要创建String范例 的对象,String对象是在运行时才加载到内存的堆中的,属于运行时创建,以是 要先在堆中创建一个String对象,再去常量池中探求 是否有雷同 的字符串,假如 有就返回堆中Sring对象的引用,假如 没有则在将该字符串加入常量池中。

举个栗子:

比较下列两种创建字符串的方法:

String str1 = new String("abc");

String str2 = "abc";

答案:第一种是用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。 运行时期创建 。

第二种是先在栈中创建一个对String类的对象引用变量str2,然后通过符号引用去字符串常量池里找有没有”abc”,假如 没有,则将”abc”存放进字符串常量池,并令str2指向”abc”,假如 已经有”abc” 则直接令str2指向“abc”。“abc”存于常量池在 编译期间完成 。

String s = new String("abc")
这条语句创建了几个对象?

答案:共2个。第一个对象是”abc”字符串存储在常量池中,第二个对象在Java Heap中的 String 对象。这里不要混淆了s是放在栈内里 的指向了Heap堆中的String对象。

String s1 = new String("s1") ;

String s1 = new String("s1") ;

上面一共创建了几个对象?

答案:3个 ,编译期常量池中创建1个,运行期堆中创建2个.(用new创建的每new一次就在堆上创建一个对象,用引号创建的假如 在常量池中已有就直接指向,不用创建)

总结

本篇文章就到这里了,盼望 可以或许 给你带来帮助,也盼望 您可以或许 多多关注脚本之家的更多内容!


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

avatar 当当当当裤裆坦 | 2021-9-13 00:20:22 | 显示全部楼层
精华帖的节奏啊!
回复

使用道具 举报

avatar 精诚通潭 | 2021-10-2 16:33:03 | 显示全部楼层
经典!
回复

使用道具 举报

谢谢admin楼主的分享!
回复

使用道具 举报

十分赞同admin楼主!
回复

使用道具 举报

学习雷锋,好好回帖!
回复

使用道具 举报

avatar 宇宙无限 | 昨天 17:25 | 显示全部楼层
admin楼主很有艺术范!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则