記錄建立String的兩種方式,"" 和 new String()區別,String intern方法的使用和常量池。java
package com.com.string;
/** * @Auther: lantao * @Date: 2019-04-15 13:53 * @Company: 隨行付支付有限公司 * @maill: lan_tao@suixingpay.com * @Description: TODO */
public class StringTest {
public static void main(String[] args) {
// 使用 "" 建立 會直接存儲在 常量池中
String a = "lantao";
// 使用 new String 建立, 會將zahngsan存儲到常量池中,而後在Heap中建立對象指向b
String b = new String("zhangsan");
// 使用 字符串鏈接符拼接 ,會直接存儲 'wangwuzhaoliu' 字符串在常量池中
String c = "wangwu" + "zhaoliu";
// 使用字符串 "引用" 拼接 ,不執行 intern 方法,不會存放到常量池中,可是會將 --- 存入到常量池中
String d = a + "---";
// 使用 new String 拼接 ,不執行 intern 方法,不會存放到常量池中,可是會將wang 和 jiu 兩個字符串存到常量池中
String f = new String("wang") + "jiu";
// 使用 new String 拼接 ,不執行 intern 方法,不會存放到常量池中, 可是會將 zhao 和 ba 兩個字符串存入到常量池中
String g = new String("zhao") + new String("ba");
}
}
複製代碼
字符串拼接git
public class StringTest {
public static void main(String[] args) {
String a = "lan" + "tao";
}
}
複製代碼
lan 和 tao 都是字符串,都是在編譯器可知的,編譯器會將這行代碼優化,當一個字符串是由多個可知的字符串(非引用字符串)鏈接組成,將會優化爲以下。github
public class StringTest {
public static void main(String[] args) {
String a = "lantao";
}
}
複製代碼
JVM會將字符串"lantao"放入到String常量池中。app
引用拼接:ide
public class StringTest {
public static void main(String[] args) {
String a = "lan";
String b = a + "tao";
// 上下含義相同
String c = "zhang";
String d = "san";
String f = c + d;
}
}
複製代碼
當Java編譯器遇到字符串引用 或 字符串引用和可知字符串拼接的時候,會建立一個StringBuilder
對象,後面的append()。優化
由於有字符串引用存在,而引用的值在程序編譯期是沒法肯定的。另外 "lan"、"tao" 都會編譯器添加到字符串常量池中(若是沒有的話),由於它們都是編譯期肯定的字符串常量,可是最後的"lantao"並不會添加到字符串常量池, 除非執行b.intern() 方法ui
final拼接spa
public class StringTest {
public static void main(String[] args) {
final String a = "lan";
final String b = "tao";
String c = a + b + "2019";
}
}
複製代碼
final拼接和以上二者的區別就是在前邊增長了final修飾,用final修飾的字符串就是在編譯期可知的,編譯期就會將以上代碼優化爲.net
public class StringTest {
public static void main(String[] args) {
String str = "lantao2019";
}
}
複製代碼
這裏 final 拼接的效果是和字符串拼接是一致的。code
String.intern()是一個Native(本地)方法,它的做用是若是字符串常量池已經包含一個等於此String對象的字符串,則返回字符串常量池中這個字符串的引用, 不然將當前String對象的引用地址(堆中)添加到字符串常量池中並返回。
注意:基本數據類型之間的 == 是比較值,引用數據類型 == 比較的是地址值
public class StringTest {
public static void main(String[] args) {
// 基本數據類型之間的 == 是比較值,引用數據類型 == 比較的是地址值
// 1:在Java Heap中建立對象 2:在字符串常量池中添加 zhangsan
String a = new String("zhangsan");
// 調用 intern 方法,因上一步中已經將zhangsan存入常量池中,這裏直接返回常量池 zhangsan 的引用地址
String b = a.intern();
// a 的地址在Java Heap中 , b的地址在 常量池中 ,因此結果是flase
System.out.println(a == b);
// 由於常量池中已經包含zhangsan,因此直接返回
String c = "zhangsan";
// b c 的地址一致,因此是true
System.out.println(b == c);
}
}
//結果
false
true
複製代碼
解釋:
1:在Java Heap中建立對象而後在字符串常量池中添加 zhangsan。
2:調用 intern 方法,因上一步中已經將zhangsan存入常量池中,這裏直接返回常量池 zhangsan 的引用地址。
3:因 a 的地址在Heap中,b的地址在字符串常量池中。
4:由於常量池中已經包含zhangsan,因此直接返回
5: b c 的地址一致,因此是true
地址可使用System.identityHashCode(a)方法獲取
public class StringTest {
public static void main(String[] args) {
//1: 首先會在Heap中建立對象,而後在常量池中放入zhagnsan 和 wangwu ,可是並不會放入zhagnsanwangwu
String a = new String("zhangsan") + "wangwu";
// 2:調用 intern ,由於字符串常量池中沒有」zhangsanwangwu」這種拼接後的字符串,因此將堆中String對象的引用地址添加到字符串常量池中。jdk1.7後常量池引入到了Heap中,因此能夠直接存儲引用
String b = a.intern();
// 3:由於 a 的地址和 b的地址一致,鎖以是true
System.out.println(a == b);
//4:因常量池中已經存在 zhangsanwangwu 了,因此直接返回引用就是 a 類型 a ==b 鎖 a==b==c
String c = "zhangsanwangwu";
System.out.println(a == c); // true
System.out.println(b == c); // true
// 5:首先會在Heap中建立對象,而後會在常量池中存儲 zhang 和 san
String d = new String("zhang") + "san";
// 6: 返回的是 常量池中的 地址,因在a變量時已經將 zhangsan 放入到了常量池中
String f = d.inter();
System.out.println(d = f); // false
}
}
複製代碼
解釋:
1:首先會在Heap中建立對象a,而後在常量池中放入zhagnsan 和 wangwu** ,可是並不會放入zhagnsanwangwu。
2:調用 intern ,由於字符串常量池中沒有」zhangsanwangwu」這種拼接後的字符串,因此將堆中String對象的引用地址添加到字符串常量池中。jdk1.7後常量池引入到了Heap中,因此能夠直接存儲引用。
3:由於 a 的地址和 b的地址一致,因此是true。
4:因常量池中已經存在 zhangsanwangwu 了,因此直接返回引用就是 a 類型, a ==b 因此 a==b==c。
5:首先會在Heap中建立對象d,而後會在常量池中存儲 zhang 和 san。
6:因在建立對象a時,已經將 "zhangsan"放入到了常量池,因此返回的是常量池中的zhangsan地址,對象d的地址在Heap中,f的地址在常量池中,並非一個,因此false;
博客地址:lantaoblog.site