内容部分参考链接:https://www.cnblogs.com/gxyandwmm/p/9495923.html#commentform(写得更加详细和全面)

1.String是final修饰的。

2.jdk8及以前版本String是char数组存储数据,jdk9开始String是byte数组存储数据,以及有coder字段控制字符串编码。

:因为String存储单位也是final修饰的,所以String是不可变的。

3.不可变的好处

  1).可以缓存hash值,因为不可变性使得hash值也不可变

  2).String pool字符常量池需要

  3).安全性,用于网络参数

  4).线程安全

添加字符串到常量池并返回其引用的两种方式 "123".intern();和 String a = "123";

  至多创建一个对象,就是如果字符串常量池里面存在"123"的字符串,直接返回它的引用地址。

new String("123");

  至少创建一个对象,至多创建两个对象。

  一个是编译放入String pool里面指向"123"字符串,一个是new的方式放在堆里的对象

intern()函数

  在1.6中,intern的处理是 先判断字符串常量是否在字符串常量池中,如果存在直接返回该常量,如果没有找到,则将该字符串常量加入到字符串常量区,也就是在字符串常量区建立该常量;

  在1.7中,intern的处理是 先判断字符串常量是否在字符串常量池中,如果存在直接返回该常量,如果没有找到,说明该字符串常量在堆中,则处理是把堆区该对象的引用加入到字符串常量池中,以后别人拿到的是该字符串常量的引用,实际存在堆中;

测试栗子

        String str = new String("11");//创建两个对象,返回堆中的对象引用
        String str1 = str.intern();//常量池已有,返回常量池对象引用
        String str2 = "11";//同Str1
        String str3 = "11";//同Str1
        System.out.println(str==str1);//false
        System.out.println(str==str2);//false
        System.out.println(str1==str2);//true
        System.out.println(str2==str3);//true
        //实际是通过StringBuffer的append拼接之后调用toString,new出来的,所以在堆中。和直接new String("22")不同。
        //"2" + new String("2");也是如此
        String t2 = new String("2") + new String("2");
        //1.7及以后先看常量池有没有,再看堆中有没有,这时堆中有,讲堆的引用放入常量池。
        //说的是1.6是直接在常量池再创建(未实操所以占时不知道)
        String t3 = t2.intern();//这个地方1.6和1.7放入常量池是不同的
        String t4 = "22";
        System.out.println(t2 == t3);//jdk不同结果不同 1.7 true
        System.out.println(t3 == t4);//true
        String t5 = "33" + "33";//jvm编译优化,相当于"1111"
        String t6 = "3333";
        String t7 = "33";
        String t8 = "33";
        System.out.println(t5 == t6);//true
        System.out.println("33" + "33"==t6);//true jvm编译的时候遇到字符双引号会优化,即"11"+"11"相当于在编译阶段的 "1111"
        System.out.println(t7 + t8 == t6);//false(应该和上述new两个字符串对象拼接底层实现一致,上述也是参考大佬的理论)

 

 posted on 2020-03-15 13:22  いつも何度でも  阅读(207)  评论(0编辑  收藏  举报