JAVA_String
從概念上講,JAVA字串就是Unicode序列。例如"Java\u2122"由5個UNICODE字元J
,a
,v
,a
和™組成。Java沒有內建和字串型別,而是試用java標準庫中提供的一個預定義類,很自然地叫做了string
。
子串substring
String subStr = str.substring(beginIndex);
這裡 beginIndex
指的是子字串開始位置的索引(包括該位置的字元),結束位置是字串的末尾。
String str = "hello";
System.out.println(str.substring(0,3)); //'hel'
過載版本:
String subStr = str.substring(beginIndex, endIndex);
在這個版本中,beginIndex
和 endIndex
分別指定了子字串開始和結束的位置。注意 endIndex
不包含在子字串內,即子字串包含索引為 beginIndex
到 endIndex - 1
的字元。
拼接
與絕大多數語言一樣,Java允許使用+號連線兩個字串
String str = "ivanlee";
String str1 = "regina";
System.out.println(str+str1);//ivanleeregina
當將一個字串與一個非字串的值進行拼接時,後者迴轉換成字串,且任何一個java物件都可以轉換成字串。
String str = "ivanlee";
int no = 7;
System.out.println(str+no);//ivanlee7
在java11當中,還提供了repeat
方法
String str = "ivanlee".repeat(3);//ivanleeivanleeivanlee
字串不可變
String類沒有提供任何方法來修改字串的某個字元。如果希望將字串內容修改,不能直接對字串進行修改,只能對字串進行讀取和拼接,比如'ivanlee'把最後的ee改成aa只能是
String str = "ivanlee";
String newstr = str.substring(0,5) + "aa";
這樣不能修改字串有一個很大的優點就是編譯器可以讓字串共享。
想象各個字串存放在一個公共儲存池裡,字串變數指向儲存池中相應的位置。如果複製一個字串變數,原始字串和複製的字串共享相同的字元。
字串相等
equals()
和equalsIgnoreCase()
函式分別比較區分大小寫的字串以及忽視大小寫的字串。
String str = "ivanlee";
String newstr = "iVanlee";
System.out.println(newstr.equals(str)); //false
System.out.println(str.equalsIgnoreCase(newstr)); //true
不要使用運算子檢測兩個字串,這個運算子只能夠確定兩個字串是否存放在同一個位置。所以相同的字串副本可能會放在不同的位置上。如果虛擬機器總是共享相等的字串,則可以使用運算子檢測字串是否相等。但實際上只有字串字面量會共享。而+或者substring等操作得到的字串並不共享。因此,千萬不要使用==來測試是否相等。
String s1 = "abc"; // 字串字面量,s1 指向字串池中的 "abc"
String s2 = "abc"; // s2 也指向字串池中的 "abc",s1 == s2 返回 true
String s3 = new String("abc"); // 建立了一個新的物件,不在字串池中
String s4 = "abc"; // s4 指向字串池中的 "abc"
// s3 和 s4 內容相同,但不是同一個物件,因此 s3 == s4 返回 false
String s5 = "ab" + "c"; // 字串連線,結果仍然會在字串池中查詢或建立 "abc"
String s6 = "abc"; // s6 指向字串池中的 "abc"
// s5 和 s6 都指向字串池中的 "abc",因此 s5 == s6 返回 true
String s7 = "abc".substring(0, 3); // 使用 substring 方法,結果不在字串池中
String s8 = "abc"; // s8 指向字串池中的 "abc"
在 Java 8 及之前的版本中,substring
方法返回的字串不會自動放入字串池中,因此 s7
和 s8
儘管內容相同,但它們不是同一個物件。因此 s7 == s8
將返回 false
。從 Java 9 開始,JEP 282(String Concatenation Optimization)引入了最佳化,使得某些字串操作(包括 substring
方法)的結果在某些情況下可能會被放入字串池中,但這取決於 JVM 的實現細節。
碼點和程式碼單元
在Java中,“碼點”(code point)和“程式碼單元”(code unit)是與Unicode字元編碼相關的術語。它們之間的關係主要體現在Java如何處理Unicode字元上。
碼點指的是Unicode標準中定義的唯一識別符號,用於唯一地標識一個字元。Unicode標準覆蓋了所有的字符集,從ASCII到各種語言的文字元號,甚至到數學符號和表情符號。每一個字元都有一個唯一的碼點,這個碼點是一個整數值。Unicode碼點範圍從U+0000到U+10FFFF,共包含了超過110萬個可能的字元。
程式碼單元是指在特定編碼方案中表示一個字元所需的位數。在Java中,字元是以16位(兩個位元組)的Unicode程式碼單元儲存的,這是因為Java的 char 型別是16位的無符號整數。
Java中的字元表示:
基本多文種平面(BMP)字元:這些字元的碼點範圍是從U+0000到U+FFFF,可以直接用一個 char 型別表示。Java中的大多數字符都屬於這一類。
代理項(Surrogate Pairs):對於超出BMP範圍的字元(即碼點大於U+FFFF),需要使用一對代理項來表示。這對代理項由一個高位代理項(high surrogate)和一個低位代理項(low surrogate)組成,每個代理項也是一個 char 型別。
高位代理項的碼點範圍是U+D800到U+DBFF。
低位代理項的碼點範圍是U+DC00到U+DFFF。
// BMP字元可以直接用一個char表示
char c1 = 'A'; // 碼點 U+0041
System.out.println(c1);
// 非BMP字元需要兩個char表示(代理項)
String emoji = "😀"; // 碼點 U+1F600
System.out.println(emoji.codePointCount(0, emoji.length())); // 輸出 1,因為只有一個碼點
// 檢視具體的碼點值
int codePoint = emoji.codePointAt(0);
System.out.println(codePoint); // 輸出 U+1F600 的值
// 獲取具體的程式碼單元序列
for (int i = 0; i < emoji.length(); i++) {
char codeUnit = emoji.charAt(i);
System.out.println("Code unit: " + codeUnit);
}
Code point count: 1
Code unit: ᘔ
Code unit: ᗩ
Code point value: 128512
java.lang.string
-
char charAt(int index)
返回給定位置的程式碼單元。除非對底層的程式碼單元感興趣,否則不需要呼叫這個方法。 -
int codePointAt(int index) 返回從給定位置開始的碼點。
-
int offsetByCodePoints(int startIndex, int cpCount)
返回從 startIndex 碼點開始,cpCount個碼點後的碼點索引。 -
int compareTo(String other)
按照字典順序,如果字串位於other之前,返回一個負數;如果字元申位於other 之後,返回一個正數;如果兩個字串相等,返回0。 -
IntStream codePoints()
將這個字串的碼點作為一個流返回。呼叫toArray將它們放在一個陣列中。 -
new String(int[] codePoints, int offset, int count)
用陣列中從 offset 開始的count個碼點構造一個字串。 -
boolean isEmpty( )
boolean isBlank()
如果字串為空或者由空白符組成,返回true。 -
boolean startsWith(String prefix) boolean endsWith(String suffix)
如果字串以prefix開頭或以 suffix或結尾,則返回 true。 -
int indexof(String str)
-
int index0f(String str, int fromIndex)
-
int indexOf(int cp)
-
int index0f(int cp, int fromIndex)
返回與字串 str或碼點cp相等的第一個子串的開始位置。從索引日或 froaIndex開始
匹配。如果 str或 cp不在字串中,則返回-1。 -
int lastIndexOf(String str)
-
int lastIndexOf(String str, int fromIndex)
-
int lastindexOf(int cp)
-
int lastindexOf(int cp, int fromIndex)
返回與字串 str或碼點 cp相等的最後一個子串的開始位置。從字串末尾或 froaInde
開始匹配。如果 str或cp不在字串中,則返回-1。 -
int length() 返回字串程式碼單元的個數。
-
int codePointCount(int startIndex,int endIndex)
返回 startIndex到endIndex-1之間的碼點個數。 -
String replace(CharSequence oldString, CharSequence newString)
返回一個新字串,這是用 nestring替換原始字串中與oldString匹配的所有子串得到的。可以用String或StringBuilder物件作為CharSequence 引數。 -
String substring(int beginIndex)
-
String substring(int beginIndex, int endIndex)
返回一個新字串,這個字串包含原始字串中從beginIndex到字串末尾或endIndex-1的所有程式碼單元。 -
String toLowerCase()
String toUpperCase()
返回一個新字串,這個字串包含原始字串中的所有字元,不過將原始字串中的大寫字母改為小寫,或者將原始字串中的小寫字母改成大寫母。String strip() -
String stripLeading()
String stripTrailing()
返回一個新字串,這個字串要刪除原始字串頭部和尾部或者只是頭部或尾部的空白符。要使用這些方法,而不要使用古老的trim方法刪除小於等於U+0020的字元。 -
String join(CharSequence delimiter, charSequence...elements)
返回一個新字串,用給定的定界符連線所有元素。構建字串
有些時候,需要由較短的字串構建字串。例如:按鍵或者檔案中的單詞。如果採用字串拼接的方式來達到這個目的,效率會很低。每次拼接字串時,都會構建一個新的string物件,又耗時又浪費空間。使用
StringBuilder
類來避免這個問題。StringBuilder builder = new StringBuilder(); //當每次需要新增另外一部分時,就呼叫append方法 builder.append('i'); builder.append("vanlee"); //字串構建完成時,呼叫tostring方法就得到一個string物件,其中包含了構建器中的字元佇列 String completedString = builder.toString(); //builder: ivanlee //completedString: ivanlee
-
StringBuilder()
構造一個空的字串構建器。 -
int length()
返回構建器或緩衝器中的程式碼單元個數。 -
StringBuilder append(String str)
追加一個字串並返回this。 -
StringBuilder append(char c)
追加一個程式碼單元並返回this。 -
StringBuilder appendCodePoint(int cp)
追加一個碼點,將它轉換為一個或兩個程式碼單元並返回 this。 -
void setcharAt(int i,char c)
將第i個程式碼單元設定為c。 -
StringBuilder insert(int offset, String str)
在 ofset 位置插入一個字串並返回 this。 -
StringBuilder insert(int offset, char c)
在 ofset 位置插人一個程式碼單元並返回 this。 -
StringBuilder delete(int startIndex, int endIndex)
刪除從 startIndex到endIndex-1的程式碼單元並返回 this。 -
String toString()
返回一個字串,其資料與構建器或緩衝器內容相同