细化探讨字符串常量池问题

注:本文中常量池均指字符串常量池

本博客目标:

1、1.8及其之前 字符串常量池理解
2、1.8常量池的优化
3、1.6、1.7、1.8常量池对比。(待更新)


内容:

1. 常量池和堆的理解

首先先看这个代码

		String s2 = "1";
        String s3 = s2.intern();
        String s1 = new String("1");

        System.out.println("s1 == s2    "+(s1 == s2));
        System.out.println("s2 == s3    "+(s2 == s3));
        System.out.println("s1 == s3    "+(s1 == s3));

运行结果是:s2==s3为true,其余为false。此时无论怎么更换位置,结果是不会变的。
结果分析:s2=“1”,这个并未在堆中创建对象,直接在常量池中寻找是否存在字符串“1”,若不存在则在常量池中创建一个“1”字符串。然后返回常量池中唯一的那个字符串“1”地址。s2.intern(),这句话会首先判断s2指向的字符串(在这里指向"1")是否存在常量池中,若存在则返回该字符串的应用,若不存在则在常量池中创建该对象(1.7之前,1.7之后为将对象的引用放入常量池中,但是在该例子中没影响,后文会继续分析)。因此s3指向的也是常量池中的对象(严格来说应该是“1”的引用)。
String s3=new String(“1”),该句因为包含new,因此在堆中创建String对象“1”,然后准备往常量池中添加"1"对象,若常量池中已经存在则不做处理直接返回堆中的“1”对象的应用;若常量池中没有“1”对象,此时会在常量池中创建“1”对象,然后返回堆中的“1”对象。
综上:s2、s3指向常量池中的“1”对象,而s1指向堆中对象。因此s1!= s2 == s3

小总结:若存在new关键字,则其一定会在堆中创建一个不一样的对象。若仅存在“1”,则只会在常量池中创建。

2. 1.8关于常量池的优化

针对1.8的特性您可能要对比着看下这两个代码

--------------------------代码1-------------------------------
1		String s1 = new String("1")+new String("1");
2      String s2 = "11";
3      String s4 = s2.intern();
4      String s3 = new String("11");
        
--------------------------代码2-------------------------------
1		String s1 = new String("1")+new String("1");
2      String s4 = s1.intern();
3      String s2 = "11";
4      String s3 = new String("11");
--------------------------输出-------------------------------
        System.out.println("s1 == s2    "+(s1 == s2));
        System.out.println("s2 == s3    "+(s2 == s3));
        System.out.println("s1 == s3    "+(s1 == s3));
        System.out.println("s1 == s4    "+(s1 == s4));
        System.out.println("s2 == s4    "+(s2 == s4));
        System.out.println("s3 == s4    "+(s3 == s4));

读者可以先试着猜一下这两个结果有什么区别。

运行结果:代码1中仅s2==s4,其余均不相等。代码2中s1 == s2 ==s4。
结果分析:
代码1中:行1中因为有两个new关键字,因此会在堆中创建两个“1”对象。而s1并不是由一个完整的new关键字构建的对象,其是由两个new对象的组件的,因此其仅仅会在堆中创建一个"11"对象,并不会在常量池中创建(详解见总结),因此s1指向的是堆中的“11”对象。s2由上文可知其只在常量池中创建对象“11”。而行3中,因为常量池中已有行2创建的“11”对象,因此s4和s2一样指向行2创建的常量池中“11”对象的引用。而行3的s3就是个配角,便于我们回顾下上文,s3在常量池和堆中均创建“11”对象,但是其指向堆中的对象。
代码1总结:s1、s3指向堆中对象,s2、s4指向常量池中对象。
代码2中:行1和代码1中的一样。行2和之前有区别了,因为在1.8中,intern()和之前不太一样了,此时1.8的inten()也是会判断s1的对象在常量池中是否存在,若存在和原来一样;若不存在,则在常量池中创建一个指向s1的应用。注意:此时创建的是指向s1的应用,不用创建对象了,也就是说常量池中此时是占着“11”对象的坑,但是返回的却不是常量池中应该存在的“11”对象,而是此时在占常量池中“11”坑的堆中“11”对象的引用,其返回的不再是常量池中“11”对象的地址,而是堆中“11”对象的地址。因此此时的s4指向的是行1在堆中创建的对象。行3中,因为常量池“11”的坑已经被占,因此其返回的也是常量池中的地址即行1的地址。而行4的s3依旧是新创建的堆中对象“11”,因此s1 == s2 ==s4。

小总结:
String s1 = new String(“1”)+new String(“1”)+new String(“1”)和
String s1 = new String(“1”)+“1”+“1”。效果几乎一样,只在堆中创建“111”对象。
String s1 =“1”+“1”+“1”。只在常量池中创建对象“111”。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值