JVM-常量池

来源:互联网 发布:深圳飞扬数码通讯淘宝 编辑:程序博客网 时间:2024/05/29 08:39
学习JVM之后,发现对常量池的理解又深入了一些。下面就从JVM的层面去理解JAVA程序中那些常见的语句。
读过笔者博客“JVM-类的生命周期“http://yizhenn.iteye.com/blog/2290619的读者都应该已经知道,JVM在加载class文件时经历了装载,连接,初始化的过程,其中连接又包括验证,准备和解析。我们就来说说这个解析。

所谓解析,就是将class文件中的静态常量池中的符号引用解析为直接引用,说白了,就是为class常量池中的一些常量创建对象。比如String str="abc";理论上来讲直接在class静态常量池中存放"abc"即可。但是我们知道,JAVA中除了8种基本类型之外,其他的都是引用。因此,对于静态常量池中的"abc",JVM会在堆中创建一个对象,静态常量池中的str就指向这个刚刚创建的对象。像str这样的常量对象所在的空间,叫做动态常量池。

在JAVA中,String和Integer,Short,Long,Character,Boolean,Byte这六种基本类型的封装类都实现了动态常量池机制。对于六种基本类型的封装类,我们以Integer为代表进行说明。

如下代码:
String a="123";String b="123";

在解析的时候,发现静态常量池中有a="123",就会在动态常量池中寻找是否有值为"123"的对象,结果没有找到,就会执行new String("123"),然后使静态常量池中的a指向该对象,当发现静态常量池中有b="123",就会在动态常量池中寻找是否有值为"123"的对象,结果找到了之前创建的那个对象,就会把那个对象的地址返回给静态常量池中的b。

上面的过程是在解析的时候做的,当然你也可以认为在执行的时候做的。但不管怎样,一定存在一个常量池,当执行String str="xx";的时候,先到常量池中去寻找值为xx的对象,如果存在,就直接返回该对象地址,否则在动态常量池中创建一个新对象并返回地址。

如下代码:
String a=new String("123");String b=new String("123");

第一行代码在执行的时候,JVM见到"123",会先到动态常量池中看是否有值为"123"的对象,如果没有,在常量池中创建一个对象String("123").这个过程和a没有半毛钱关系,你可以认为这是JVM常量池自学习的过程。接着,在堆区创建一个对象String("123");并将该对象的引用返回给a;
第二行代码也是这样的过程,所以上面的两行代码可能产生2或3个对象。

对于String类,还存在一个str.intern()方法,他的作用是检查动态常量池中是否存在值与str对象相同的对象,如果存在,直接返回该对象的引用。如果不存在,就在常量池中创建一个对象,然后返回他的引用。
如下代码:
String a="123";String b="123";String c=new String("123");String d=c.intern();

对于上面的代码,你应该能理解,a和b和d都指向的是动态常量池中的那个对象String("123"),而c指向的是堆中的对象String("123");

介绍了String类的常量池,我们来说Integer类的常量池。Integer类型的取值不像String类型那么广泛,String常量池中的对象收集自程序。Integer常量池中的对象是固定的,只有取值为-128~127的这256个对象。当Integer.valueOf(i)中i的值是-128~127时,直接返回常量池中的对象,否则在堆区新建一个对象并返回他的引用。这可以从jdk源码中得到证明,在jdk源码中,Integer有这样的一个方法:
    public static Integer valueOf(int i) {        assert IntegerCache.high >= 127;        if (i >= IntegerCache.low && i <= IntegerCache.high)            return IntegerCache.cache[i + (-IntegerCache.low)];        return new Integer(i);    }


这个方法是自动装包时候用的方法,何谓装包?把int这个基本类型转化为Integer这个引用类型就是装包。
代码如下:
Integer a=1;Integer b=1;Integer c=1111;Integer d=1111;

对于上面的代码,实际上如下:
Integer a=Integer.valueOf(1);Integer b=Integer.valueOf(1);Integer c=Integer.valueOf(1111);Integer d=Integer.valueOf(1111);

因此a和b指向Integer常量池中的同一个对象,他们的值相等。c和d指向堆区中的不同对象,他们的值不等。

如下代码:
Integer a=new Integer(1);Integer b=new Integer(1);

由于使用了new,强制的在堆区创建了两个对象,没用到常量池优化,因此a和b的值不等。

这里顺便提一下装包和拆包,将基本类型转化为对应的封装类的过程叫装包,反之叫拆包。当基本类型和其对应的封装类执行比较的时候,比如Integer对象和int型比较,这会使用拆包,将Integer类型拆包为int,这个过程调用Integer的intValue()方法。

关于上面提到的其余5中包装类的常量池与Integer类似,在此不再赘述。
0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 老婆出轨离婚又舍不得家我该怎么办 怀孕一个月刚刚自慰有点流血怎么办 老公出轨还不知道悔改妻子怎么办 离婚了前妻户口还在再婚怎么办 怀孕六个月内裤老是湿有异味怎么办 怀孕五个月内裤总是湿有异味怎么办 耳朵里面有个洞老是流水冒浓怎么办 宝宝拉粑粑有臭酸味怎么回事怎么办 老婆晚上回家内裤是湿的尿味怎么办 怀孕五个月下身痒内裤湿怎么办 哺乳期奶水太多经常弄湿衣服怎么办 麻料裙子一坐下就皱怎么办 不小心把答题卡弄皱了怎么办 嘴巴又干又黏又臭怎么办 不小心把红枣核吞了怎么办 小天才电话手表被偷了怎么办 18k金被火烧黑了怎么办 衣服掉色染到别的衣服上怎么办 夏天太阳太毒刚发芽的花种子怎么办 长斑了怎么办 喝玫瑰花茶能祛斑吗 烧纸火纸迷信纸利润太低怎么办 刚买的绣球花花有点蔫怎么办 ZF葡7正常佩戴动能太满怎么办 怀孕初期老婆婆做的菜不好吃怎么办 调节协议已签字不签收调解书怎么办 给晋中苗圃拉了树苗没拿上钱怎么办 多肉旁边长出好多小株怎么办 烤瓷牙制备时颌关系不够怎么办 对门放石头正对我家大门怎么办 合租的室友关门开门特别大声怎么办 三周岁的宝宝小阴唇再次粘连怎么办 小阴唇内侧长了毛囊炎很大疼怎么办 小阴唇上一个黄豆大的硬疙瘩怎么办 梦幻西游手游金币兑换上限了怎么办 手机放裤子口袋里易拔出怎么办 两个月宝宝拉肚子怎么办吃纯母乳 花王泡沫染停留时间太久怎么办 ps右下角的图层图标隐藏了怎么办 压缩包文件太大微信无法传送怎么办 一寸照片的尺寸在ps中怎么办 遇到尖酸刻薄爱数落人的领导怎么办