必須知道的String知識點
1.String 類型的概述
Java中String就是Unicode字符序列,例如,字符串“Java\u2122”由5個Unicode字符J、a、v、a和 ? 組成。不像C/C++中,字符串只是字符數組,Java中字符串String是一個java.lang包中的類。
但是,在Java中String和普通的類不一樣,是一個特殊的類:
- String可以直接使用雙引號""進行賦值,而不用調用構造函數。
- ‘+‘可以拼接兩個字符串,但是其他對象不能使用‘+‘。
- String是不可變的,也就是說,String對象一旦創建就不能被修改。例如,toUpperCase() 方法創建並返回一個新字符串,而不是修改原理字符串的內容。
String類型的常用方法總結:
// 長度 int length() // 返回字符串的長度 boolean isEmpty() // 判斷長度是否==0 // 比較 boolean equals(String another) // Java中不能使用 '==' 或者 '!=' 來比較兩個字符串 boolean equalsIgnoreCase(String another) int compareTo(String another) // 返回 0 如果字符串相同;< 0 如果字典序小於another;否則 > 0 int compareToIgnoreCase(String another) boolean startsWith(String another) boolean startsWith(String another, int fromIndex) // 在fromIndex位置開始 boolean endsWith(String another) // 檢索 & 索引下標 int indexOf(String search) int indexOf(String search, int fromIndex) int indexOf(int character) int indexOf(int character, int fromIndex) int lastIndexOf(String search) int lastIndexOf(String search, int fromIndex) int lastIndexOf(int character) int lastIndexOf(int character, int fromIndex) // 截取字符串的字符或一部分字符串(子串) char charAt(int index) // 下標從 0 到 length - 1 String substring(int fromIndex) String substring(int fromIndex, int endIndex) // 包前不包後 // 根據原字符串創建一個新字符串或字符數組 String toLowerCase() String toUpperCase() String trim() // 返回一個移除前後空白的新字符串 String replace(char oldChar, char newChar) // 返回一個替換後的字符串 String concat(String another) // 字符串拼接 char[] toCharArray() // 返回一個字符串數組 void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) // 復制到 dst 字符數組中 // 靜態方法,將基本類型轉換為字符串 static String valueOf(type arg) // type可以是基本類型或者字符數組 // 靜態方法,將字符串進行格式化輸出 static String format(String formattingString, Object... args) // 類似於printf() // 正則表達式 boolean matches(String regex) String replaceFirst(String regex, String replacement) String replaceAll(String regex, String replacement) String[] split(String regex) String[] split(String regex, int limit)
靜態方法 String.format()
這個方法用來輸出一個格式化的字符串,類似於 C 系列的 printf() 函數。例如,
String.format("%.1f", 1.234); // 返回字符串 "1.2"
String.format() 可以非常方便地用來輸出一個簡單格式的字符串(比如,在 toStirng() 方法中使用)。對於復雜的字符串,使用StringBuffer/StringBuilder加一個Formatter。
2. String 一個特殊的類
因為程序會頻繁的使用 String 類型,String 類型在Java中是很特殊的。自然,為了計算性能和存儲效率,String 的性能很關鍵。為了提高提高語言的性能,Java設計者們在面向對象語言中,保留了基本數據類型,而不是一切都是對象。基本數據類型存儲在調用棧上,從而占用更少的存儲空間,以及更容易維護。而對象實例存儲在堆上,需要更復雜的內存管理和更多的存儲空間。
為了更好地性能,Java 的 String 被設計成介於基本數據類型和普通類之間的一個特殊類型。Stirng 的特性包括:
- 用於基本數據類型操作的‘+‘,被 String 重載用來拼接兩個字符串。出於軟件工程的考慮,Java 不支持操作符的重載。在支持操作符重載的語言中,比如 C++ ,甚至可以將 ‘+‘ 重載用來執行減法運算,這會使得代碼難以閱讀。Java 中 ‘+‘ 只被內部重載用於字符串拼接。‘+‘ 並不能用於任意兩個對象中,比如 Points 或者 Circles。
String 有兩種創建方式:直接賦值 或者 通過 new 關鍵字創建(這種方式不推薦,也不常見)
舉個例子:String str1 = "Java is Hot"; // 隱式地通過 String 字面量創建 String str2 = new String("I'm cool"); // 顯式地使用 new 創建
在第一條語句中,str1 被申明為一個 String 類型引用,並被 String 字面量 "Java is Hot" 初始化。在第二條語句中,str2 被申明為一個 String 類型引用,並通過 new 關鍵字構造的 "I‘m cool" String 對象初始化。
Stirng 字面量存儲在常量池中,相同內容的字符串是共享的,只會存儲一份。通過 new 創建的 String 對象存儲在堆上,相同內容的字符串不會共享。
2.1 String 字面量 VS String 對象
如上所述,有兩種方式構造 String :通過 String 字面量隱式地構造,或者通過 new 顯式地創建。比如:
String s1 = "Hello"; // String 字面量
String s2 = "Hello"; // String 字面量
String s3 = s1; // 相同的引用
String s4 = new String("Hello"); // String 對象
String s5 = new String("Hello"); // String 對象
Java 提供一個特別的機制,字符串常量池,來保存 String 字面量。如果兩個 String 字面量內容相同,它們將會在字符串常量池中共享。頻繁使用的字符串將會通過這種方式持久地保存。另一方面,通過new 創建的 String 對象被保存在堆中。每個存儲在堆上的 String 對象,就像其他對象一樣,擁有獨立的存儲地址。堆上的存儲地址不會共享,即使兩個 String 對象內容相同。
可以使用 String 類的 equals() 方法比較兩個字符串的內容。也可以使用 ‘==‘ 來比較兩個對象的引用(或者叫指針)。看看下面的代碼:
s1 == s1; // true, 相同的引用
s1 == s2; // true, s1 和 s2 在常量池中共享
s1 == s3; // true, s3 被賦值為 s1 的引用
s1.equals(s3); // true, 內容相同
s1 == s4; // false, 對象引用不同
s1.equals(s4); // true, 內容
s4 == s5; // false, 堆上的引用不同
s4.equals(s5); // true, 內容相同
重點:
- 在上面的例子中,通過‘==‘比較兩個 String 對象的引用,說明了字符串存儲在常量池和存儲在堆上的區別。在程序中,使用 (str1 == str2) 來比較兩個字符串的內容是邏輯上的錯誤。
- String 直接賦值的內容將存儲在字符串常量池中。不推薦使用 new 去創建一個堆上的字符串對象。
2.2 String 的不可變特性
因為字符串在常量池中是共享的,Java 的 String 被設計成不可變的。也就是說,一旦 String 被創建,它的內容就不能被修改。否則,其他共享內容的 Stirng 引用將會被無法預料變化影響。類似於 toUpperCase() 的方法就可能修改 String 對象的內容,而實際上它將返回一個新創建的 String 對象,原本的 String 對象引用會被釋放,一旦沒有引用了,就將會被GC。
因為 String 是不可變的,頻繁修改 String 的效率很低(這將創建大量的字符串,並占用內存空間)。比如下面這段代碼:
// 效率低的代碼
String str = "Hello";
for (int i = 1; i < 1000; ++i) {
str = str + i;
}
如果需要頻繁修改字符串,可以考慮使用 StringBuffer 或者 StringBuilder。
3. StringBuffer & StringBuilder
如前所述,字符串是不可變的,因為存儲在字符串常量池中的字面量是共享的。修改其中一個字符串的內容,將會對其他共享的字符串產生副作用。
JDK 提供了兩個類來支持可變的字符串:StringBuffer 和 StringBuilder(都在核心包 java.lang 中)。StringBuffer 和 StringBuilder 對象跟其他普通對象一樣,存儲在堆上,不會共享,因此修改它們不會對其他對象產生副作用。
StringBuilder 類是在JDK 1.5中引入的。它基本上與 StringBuffer 一致,除了它是線程不安全的以外。對於單線程的程序來說,StringBuilder 因為沒有同步的開銷,效率會更高。
必須知道的String知識點