要了解String類型的特性,首先了解java的基礎知識。
一、 基本數據類型和引用數據類型
JVM中使用棧來存儲方法以及非全局的變量,對於基本類型來說,棧中既存變量又存值,基本類型有8種:boolean, byte,short,int, long,float, double, char, 不是基本類型的類型稱為引用類型,對於引用類型來說,棧中存變量及對象內存地址,對象內存地址指向實際對象實例。String 就是引用數據類型。基本數據類型之間的比較使用"==", 引用類型比較通常有特定的方法如equals方法。
二、 字符串常量池
String 作為引用類型,正常來說創建應該是String str = new String("Hello");,但是String太常用,幾乎每一個類型都包含這個類型的對象,這樣創建String對象就會帶來大量的時間和空間開銷,影響程序的性能,所以JVM對String類型的創建做了優化,設計了字符串常量池替代new創建String類型,變成了String str = "Hello";String類型在創建時首先會去字符串常量池中查找是否存在該字符串,如果沒有則創建改字符串,如果有,則將引用指向該字符串。這樣設計多個變量就會指向同一個字符串對象,一個變量修改就會影響另外的引用,為了消除這種影響,String類型被設計為final修飾。字符串常量池存在JVM方法區,所以里面的字符串不會被輕易回收。
三、 方法參數的值傳遞和引用傳遞
在java中,方法參數的值傳遞和引用傳遞對應基本數據類型和引用數據類型,基本數據類型參數是值傳遞,引用數據類型是參數傳遞。值傳遞的特點是方法傳參數時,會將原變量(基本數據類型變量和值存一起)拷貝一個副本傳入方法,方法中對拷貝的副本操作並不會影響原變量。引用傳遞也會將原變量拷貝一個副本傳入方法,但是由於變量存的是引用地址,所以方法中對變量的修改會影響原變量。String是引用數據類型,也就有引用傳遞的特點,但是java中String是fina修飾的,也就是不可變的,傳入方法也不會被修改。
四、 String的創建
public static void main(String[] args) { String str = "Hello"; String str2 = "Hello"; String str3 = new String("Hello"); String str4 = new String("Hello"); String str5 = str; System.out.println("str == str2:" + (str == str2)); System.out.println("str == str3:" + (str == str3)); System.out.println("str3 == str4:" + (str3 == str4)); System.out.println("str2 == str5:" + (str2 == str5)); System.out.println("str equals str3:" + (str.equals(str3))); }
- String str = "Hello" 在創建時會在字符創常量池創建字符串對象 "Hello",
- String str2 = "Hello" 在創建時會在字符創常量池查找"Hello", 發現已存在,會指向"Hello", str == str2為true。
- str3 和 str4 在創建時都會在堆中new一個新對象實例,所以str == str3 和 str3 == str4 都是false
- String str5 = str中,str5也是指向常量池字符串, 所以 str2 == str5 為true
- String重寫了equals方法,比較是兩個String對象的值,所以str.equals(str3)為true
執行結果:
str == str2:true
str == str3:false
str3 == str4:false
str2 == str5:true
str equals str3:true
圖解String的創建:
5. String類型的參數傳遞
public static void main(String[] args) { int ii = 10; Map<String, String> map = new HashMap<>(); map.put("key", "Hello"); String str = "Hello"; String str2 = new String("Hello"); change1(ii); System.out.println("ii: " + ii); change2(map); System.out.println("map: " + JSON.toJSONString(map)); change3(str); System.out.println("str: " + str); change4(str2); System.out.println("str2: " + str2); } public static void change1(int ii) { ii = 50; } public static void change2(Map<String, String> map) { map.put("key", "world"); } public static void change3(String str) { str = "你好!"; } public static void change4(String str2) { str2 = new String("你好!"); }
- ii變量是基本數據類型int,chang1方法執行是拷貝了ii的副本並修改並不能改變ii的值。
- map變量是引用數據類型,chang2方法中操作的map和原map變量都指向同一個HashMap對象,所以chang2方法對map的修改會影響到原map
- str和str2都是引用數據類型,但是String不可被修改,所以str = "你好!" 和 str2 = new String("你好!") 都是創建一個新的對象,所以不會影響到原變量。
執行結果:
ii: 10 map: {"key":"world"} str: Hello str2: Hello