内容部分参考链接: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两个字符串对象拼接底层实现一致,上述也是参考大佬的理论)
如果随笔有啥错误,请有时间的大佬评论指出。本菜鸡会及时学习进行更改。