jdk1.8字符串创建位置问题

先了解下新建字符串的方式和位置:


String a = "a";//在常量池创建"a",将a指向常量池的"a"

String b = "b";//在常量池创建"b",将a指向常量池的"b"

String c = new String("c");//首先判断"c"是否在常量池中存在,如果不存在,先创建一个,然后再在堆中创建"c"的String对象

String d = "a" + "b";//Java中的"+"其实在编译期会进行优化的,如果加号两边都是字面量(简单理解是非引用变量),则会拼接起来,然后看字符串常量池中有没有,没有则创建。所以这里会在常量池创建"ab"

String e = a + b;//这里加号连接的是两个引用类型变量,所以,这里会被优化成new String("ab")

我们常见的题目有这么一种,请问下面一段代码创建了几个对象


String x1 =new String("a") +new String("b");

这里常量池创建了两个对象:["a","b"]

堆中创建了三个对象:["a","b","ab"]

所以一共创建了5个对象

对比字符串位置的综合题目:


public static void main(String[] args) {

        String s1 = "a"; //将"a"加入常量池。常量池:["a"]

        String s2 = "b";//将"b"加入常量池。常量池:["a","b"]

        String s3 = "a" + "b";//将"ab"加入常量池。常量池:["a",“b","ab"]

        String s4 = s1 + s2;//将"ab"加入堆。常量池:["a","b","ab"]/堆:["ab"]

        String s5 = "ab";//常量池已有"ab",s5直接指向常量池的"ab",所以s3 == s5

        String s6 = s4.intern();//由于常量池已有"ab",所以堆中"ab"入池失败,s6直接指向常量池中的"ab"

        System.out.println(s3 == s4);//s3指向常量池,s4指向堆,所以false

        System.out.println(s3 == s5);//s3和s5都指向常量池,所以true

        System.out.println(s3 == s6);//s3和s6都指向常量池,所以true



        String x2 = new String("c") + new String("d");

    //向常量池加入"c":常量池:["c"] -> 向常量池加入"d":常量池:["c","d"] -> 向堆加入"c"、"d"、"cd",堆["c"、"d"、"cd"]

        x2.intern();//将"cd"入池,且x2也指向常量池

        String x1 = "cd";//常量池已有"cd",x1直接指向常量池

        System.out.println(x1 == x2);//所以x1 == x2是true



        String y2 = new String("e") + new String("f");

    //向常量池加入"e":常量池:["e"] -> 向常量池加入"f":常量池:["e","f"] -> 向堆加入"e"、"f"、"ef",堆["e"、"f"、"ef"]

        String y1 = "ef";//常量池里加入"ef"

        y2.intern();//常量池中已有"ef",入池失败

        System.out.println(y1 == y2);//y2在堆中,y1在常量池中,所以是false

    }

这里最后一段代码,假如修改为:

        String y2 = new String("e") + new String("f");

    //向常量池加入"e":常量池:["e"] -> 向常量池加入"f":常量池:["e","f"] -> 向堆加入"e"、"f"、"ef",堆["e"、"f"、"ef"]

        String y1 = "ef";//常量池里加入"ef"

        y2 = y2.intern();//常量池中已有"ef",入池失败,y2会被赋予常量池的地址

        System.out.println(y1 == y2);//y1和y2都指向常量池,所以是true

y2 = y2.intern()时,不论常量池之前是否有y2对应的字符串,y2最终都会指向常量池
这里有一个实际场景的应用:
需要统计10000个调查者的居住小区信息,加入Map,很多人的小区名重复
这时候就可以使用这个方法减少堆内存的占用

注意当jdk的版本为1.8(1.7类似),当jdk版本为1.6时代码如下:


String x2 = new String("c") + new String("d");

    //向常量池加入"c":常量池:["c"] -> 向常量池加入"d":常量池:["c","d"] -> 向堆加入"c"、"d"、"cd",堆["c"、"d"、"cd"]

        x2.intern();//将"cd"入池,但是x2不指向常量池

        String x1 = "cd";//常量池已有"cd",x1直接指向常量池

        System.out.println(x1 == x2);//所以x1 == x2是false

intern()方法会首先判断"cd"是否在常量池中存在,如果不存在,先创建一个,如果存在,则不创建。但是x2并不会指向常量池,任然会指向堆中的对象,所以堆的对象和常量池的对象相比结果为false

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容