注1:常量池里面同样的字符串只会有一份,不会存储相同的内容(什么叫相同的内容?就是拿String的equals()方法去比较,返回true的)
注2:记住,不管是String a = "aaaa" (这里的a保存的还是地址值),还是 String a = new String("aaaa"),保存的内容都是在字符串常量池
图解String内存 : https://blog.csdn.net/qq_34626097/article/details/83119790
一.
String类: 代表字符串。 Java 程序中的所有字符串字面值(如 "abc" )都作
为此类的实例实现。
String是一个final类,代表不可变的字符序列。
字符串是常量,用双引号引起来表示。 它们的值在创建之后不能更改。
String对象的字符内容是存储在一个字符数组value[]中的。
1.String类部分源码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. /
private final char value[]; //这个就是用来保存字符串字面量各个字符的
/* Cache the hash code for the string */
private int hash; // Default to 0
*String对象的字符内容是存储在一个名称为 value的 字符数组value[]中的
- String类为什么要设计成final?为什么不可以改变?
https://www.zhihu.com/question/31345592
二.
1.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中(也是一个字符数组)。
三.String对象真的不可变吗?
详解:https://blog.csdn.net/qq_37267015/article/details/78738512
四.
String s1 = "javaEEhadoop"; //常量池里面如果没有javaEEhadoop , 那么就会造一个
String s2 = "javaEEhadoop"; //先去常量池里面找是不是已经有了该字符串(用的是重新的equals方法比较内容),常量池里面已经有了该字符串,就会复用
//s1 和 s2 指向的是常量池里面同一个对象
System.out.println(s1 == s2);//true
- 只要涉及到字符串内容的改动,原字符串都是不变动的,会在常量池里面新增一个不同的字符串
五. new 的方式创建字符串
String str = "hello"; //hello是创建在字符串常量池里面的,变量str里面保存的是地址值
String s1 = new String("hello"); //在堆空间开辟一个内存空间,保存字符串常量池里面hello的地址值
六 . 比较特殊的
String字符串拼接原理:https://blog.csdn.net/qq_45800640/article/details/120284367
在拼接操作中,只要有一个不是字符串常量,就会先创建 new StringBuilder(),然后进行append操作
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop"; //字符串拼接操作中只要其中有一个是变量/new String()(只要是非常量的拼接),结果就在堆中。且变量拼接的原理是创建一个StringBuilder类的对象,调用其append方法,拼接完成后再调用该对象的toString()方法(该方法已经被重写了)返回一个字符串对象
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s5 == s6);//false
System.out.println(s5 == s7);//false
System.out.println(s6 == s7);//false
String s8 = s6.intern();//返回值得到的s8使用的常量值中已经存在的“javaEEhadoop”
System.out.println(s3 == s8);//true
intern()方法详解 :https://zhuanlan.zhihu.com/p/357872204
- StringBuilder 创建的字符数组是存放在堆里面的
采用双引号的方式来创建字符串对象 和 通过 new 关键字的方式:
https://zhuanlan.zhihu.com/p/357872204
解释的最清楚的:https://blog.csdn.net/xiaojin21cen/article/details/106404531
new StringBuilder().append("abc").append(s).toString() 创建了几个对象:
https://developer.aliyun.com/article/844237
https://juejin.cn/post/7001006646923100173 : 搜索 而这一段的本质只是创建一个新的String对象
https://blog.csdn.net/wdvbhbn/article/details/126755177
https://blog.csdn.net/qq_29951485/article/details/92785590
- java循环拼接字符串
https://blog.csdn.net/ningmengbaby/article/details/129001738
https://www.cnblogs.com/Fantasyfzg/p/16911882.html
https://blog.csdn.net/JeremyTsai/article/details/109267783
如果拼接的都是字符串直接量,则在编译时编译器会将其直接优化为一个完整的字符串,和你直接写一个完整的字符串是一样的,所以效率非常的高。
如果拼接的字符串中包含变量,则在编译时编译器采用StringBuilder对其进行优化,即自动创建StringBuilder实例并调用其append()方法,将这些字符串拼接在一起,效率也很高。
但如果这个拼接操作是在循环中进行的,那么每次循环编译器都会创建一个StringBuilder实例,再去拼接字符串,相当于执行了 new StringBuilder().append(str),所以此时效率很低。
- StringBuilder的toString方法
http://www.hzhcontrols.com/new-1221889.html
https://blog.csdn.net/guomei/article/details/17386113