一、String類概述
1、概述
java.lang.String 類代表字符串。Java程序中所有的字符串文字(例如 "abc" )都可以被看作是實現此類的實例。String 是引用數據類型,不是基本數據類型。
類 String 中包括用於檢查各個字符串的方法,比如用於比較字符串,搜索字符串,提取子字符串以及創建具有翻譯為大寫或小寫的所有字符的字符串的副本。
2、特點【重要】
a、字符串不變:字符串的值在創建后不能被更改。【非常重要】
Demo:
String s1 = "abc";
s1 += "def";
System.out.println(s1); // s1 = "abcdef"
分析:內存中有"abc","abcdef"兩個對象,s1從指向 "abc",改變指向,指向了"abcdef" ,字符串本身並沒有改變,而是改變了指向。
擴展:String對象怎么就不可變?
底層char[]數組有final修飾,意味着這個數組不能擴容等,來達到存更多的字符
char[]數組是私有的,程序員無法直接操作這個char[]數組,而且String沒有提供這樣的方法,來修改char[]數組的元素的值。
String提供的所有的方法,對字符串的修改都是給你返回一個新的字符串對象。
b、因為String對象是不可變的,可以把一些字符串存到常量池中,字符串在常量池中,可以被共享。
Demo:
String str1 = "abc";
String str2 = "abc";
分析:內存中只有一個 "abc" 對象被創建,同時被 s1 和 s2 共享。
c、字符串對象底層的存儲:
JDK1.9之前:底層是用 char[ ] 存儲
JDK1.9之后:底層選用 byte[ ] 存儲
Demo:
String str = "abc";
相當於
char datas[] = {'a', 'b', 'c'};
String str = new String(datas);
d、String 類型不能被繼承,因為 String 是由 final 修飾的。
二、String類使用步驟
1、導包
String 這個類 是 java.lang.String 包內的,不需要手動導入。
擴展:常用的如 基本數據類型,String,還有一些工具類,只要是 lang 包下面的,就不必寫 import 導包語句。
2、創建字符串
創建字符串的常見3+1種方式。(三種構造方法,一種直接創建)
a、構造方法創建
public String() : 初始化新創建的 String對象,以使其表示空字符序列
public String(char[] value) :通過當前參數中的字符數組來構造新的String。
public String(byte[] bytes) :通過使用平台的默認字符集解碼當前參數中的字節數組來構造新的String。
Demo:
// 無參構造
String str = new String();
// 通過字符數組構造
char chars[] = {'a', 'b', 'c'};
String str2 = new String(chars);
// 通過字節數組構造
byte bytes[] = { 97, 98, 99 };
String str3 = new String(bytes);
b、直接創建
String str = "字符串內容"; // 右邊直接用雙引號
分析:這里面雖然沒有 new 關鍵字,但同時創建了一個 String 對象。
三、String 對象的創建
String str = “hello”;
String s1 = new String(); // 本質上 this.value = new char[0];
String s2 = new String(String original); //this.value = original.value;
String s3 = new String(char[] a); //this.value = Arrays.copyOf(value, value.length);
String s4 = new String(char[] a,int startIndex,int count)
.......
圖解:
面試題:
(1)String str = new String("hello"); 涉及幾個對象?—— 兩個
(2)String str1 = new String("hello");
String str2 = new String("hello");涉及幾個對象?—— 三個
四、字符串是如何存儲的
字符串常量存儲在字符串常量池,目的是共享。
字符串非常量對象存儲在堆中。
字符串常量池:
1、當直接創建一個字符串時,變量會到字符串常量池中去尋找該字符串,如果找到了,該變量指向該字符串;如果沒有找到,會用 byte[ ]拼接成所需的字符串,然后放入常量池中並指向它。
2、使用 new 關鍵字創建字符串,會在堆區創建一個 String 對象,而且底層是用 byte[ ] 數組拼接的,這個 String 對象並沒有放入字符串常量池中,而是在堆中,該變量指向該對象的地址。
擴展: 字符串常量池在哪里?(Oracle官方虛擬機HotSpot)
(1)JDK1.6以及之前:方法區中
(2)JDK1.7:挪到堆中,即在堆中單獨划分了一塊字符串常量
(3)JDK1.8:從堆中挪出,挪到一個 “元空間meta space”,即類似於方法區
五、字符串的拼接
結論:
(1)因為只有常量池中才是共享,==比較才為 true;
(2)常量與常量的拼接結果在常量池中;
(3)只要其中有一個是變量,結果就在堆中;
(4)如果拼接的結果調用 intern() 方法,就在常量池中;
六、空字符串
1、表現方式
(1)String str = "";
(2)String str2 = new String();
(3)String str3 = new String("");
2、判斷是否為空
(1)if(str != null && str.length() == 0)
(2)if(str != null && str.equals(""))
(3)if("".equals(str)) 推薦
(4)if(str!=null && str.isEmpty())