JAVA的字串這篇講清楚了

ivanlee717發表於2024-09-24

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);

在這個版本中,beginIndexendIndex 分別指定了子字串開始和結束的位置。注意 endIndex 不包含在子字串內,即子字串包含索引為 beginIndexendIndex - 1 的字元。

image-20240924164847577

拼接

與絕大多數語言一樣,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"

image-20240924175224957

在 Java 8 及之前的版本中,substring 方法返回的字串不會自動放入字串池中,因此 s7s8 儘管內容相同,但它們不是同一個物件。因此 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()
    返回一個字串,其資料與構建器或緩衝器內容相同

相關文章