天天看點

[Java 基礎]字元串String類StringBuilder類StringBuffer類參考資料

String類

執行個體化String對象

String 對象初始化方式有多種。

如下代碼中,各種初始化方式的效果是一樣的,初始化後,String 對象的内容為 "hello" 。

public static void main(String[] args) {

    // 直接指派

    String str1 = "hello";

    // 構造函數方式,參數為 String

    String str2 = new String("hello");

    // 構造函數方式,參數為 StringBuilder

    String str3 = new String(new StringBuilder("hello"));

    // 構造函數方式,參數為 StringBuffer

    String str4 = new String(new StringBuffer("hello"));

    // 構造函數方式,參數為 char 數組

    char[] cz = {'h', 'e', 'l', 'l', 'o'};

    String str5 = new String(cz);

    // 構造函數方式,參數為 byte 數組

    byte[] bz = {'h', 'e', 'l', 'l', 'o'};

    String str6 = new String(bz);

    // 先使用預設構造函數,再指派

    String str7 = new String();

    str7 = "hello";

}

以上方式可歸納為兩類:

(1) 指派方式

(2) 構造函數方式

目前的Java SE8中,String類有15種構造函數,詳細看參見Java API。

傳入的參數可以是String、StringBuilder、StringBuffer、char 數組、byte 數組等等。

兩種執行個體化方式比較

一個字元串就是一個 String 類的匿名對象。

匿名對象

匿名對象就是開辟了記憶體空間的并且可以直接使用的對象。

對于這樣的代碼:

String name = "Jack";               // 指派方式初始化 String 對象

實際上就是在堆中開辟一個記憶體空間,這個空間的中存儲的值為 "Jack"。然後這個空間被 name 變量所引用。

注:在JAVA中,如果一個字元串已經被一個名稱所引用,則以後再有相同的字元串聲明時,不會重新開辟空間,而是複用之前的空間。這樣減少了不必要的空間開銷。

String str1 = "hello";

String str2 = "hello";

String str3 = "hello";

以上三個String類變量本身是存放在棧記憶體中,但是它們指向同一塊堆記憶體空間。

而如果使用構造函數方式初始化String類對象,和所有普通類一樣,隻要new一次,就會新開辟一塊堆空間。

綜上所述,可以看出指派方式要優于構造函數方式。

String的内容比較

1、使用 "=="

    String str3 = str2;

    System.out.println("str1 == str2 --> " + (str1 == str2));

    System.out.println("str1 == str3 --> " + (str1 == str3));

    System.out.println("str2 == str3 --> " + (str2 == str3));

運作結果

str1 == str2 --> false

str1 == str3 --> false

str2 == str3 --> true

從以上代碼可以看出,雖然三個字元串内容完全一緻,但是使用 "==" 去比較卻發現并不完全相等。

這是因為每個String對象的内容實際上是儲存在堆記憶體中的。是以,即使堆中的内容一緻,并不代表它們的位址空間也一緻。

"==" 是用來進行數值比較的,是以 str1 和 str2 并不相等。

2、使用equals方法

如果要比較兩個字元串的内容是否相等,可以使用 equals 方法。

    System.out.println("str1 == str2 --> " + (str1.equals(str2)));

    System.out.println("str1 == str3 --> " + (str1.equals(str3)));

    System.out.println("str2 == str3 --> " + (str2.equals(str3)));

str1 == str2 --> true

str1 == str3 --> true

String對象不可變

//: StringDemo03.java

public class StringDemo03 {

    public static String upcase(String s) {

        return s.toUpperCase();

    }

    public static void main(String[] args) {

        String a = "hello";

        System.out.println(a);    // hello

        String b = upcase(a);

        System.out.println(b);    // HELLO

} /* Output:

hello

HELLO

*///:~

當把a傳給 upcase() 方法時,實際傳遞的是引用的一個拷貝。其實,每當把 String 對象作為方法的參數時,都會複制一份引用,而該引用所指的對象其實一直待在單一的實體位置上,從未動過。

是以指向 String 的任何引用都不可能改變它的值。

不可變性會帶來一定的效率問題。例如String類的重載操作符 "+"。

注:JAVA不同于C++,并不允許程式員自定義任何重載操作符。用于String的 "+" 和 "+=" 是JAVA中僅有的兩個重載操作符。

操作符"+"可以用來拼接String。方式如下:

String s = "How " + "are " + "you?";

System.out.println(s);

/* Output:

How are you?

這種方式的問題在于,會産生一大堆需要垃圾回收的中間對象。

那麼,如何避免這種問題呢?

JAVA中提供了兩個類:StringBuilder 和 StringBuffer ,它們都有 append() 方法,效率高于 String 的 "+"。

這兩個類的差别在于 StringBuffer 是線程安全的,是以開銷也更大一些。

String類的常用方法

以下代碼是String類的一些常用方法。

public class StringDemo {

        // 擷取字元串字元個數

        System.out.println(" Goodbye ".length());

        // 擷取 String 中該索引位置上的 char

        System.out.println("Computer".charAt(4));

        // 複制 byte 到一個目标數組

        byte bytes[] = "Winter".getBytes();                // 将字元串轉為 byte 數組

        System.out.println(new String(bytes));            // 将完整 byte 數組轉為字元串

        System.out.println(new String(bytes, 1, 3));    // 将部分 byte 數組轉為字元串

        // 複制 char 到一個目标數組

        char chars[] = new char[10];

        "Summer".getChars(0, 6, chars, 2);                // 将字元串0~6位置的内容拷貝到 char 數組中,從數組位置2開始

        System.out.println(new String(chars));            // 将完整 char 數組轉為字元串

        System.out.println(new String(chars, 1, 3));    // 将部分 char 數組轉為字元串

        // 字元串轉char數組

        char[] data1 = "Baby".toCharArray();

        for (char c : data1) {

            System.out.print(c + " ");

        }

        System.out.println();

        // 如果String不包含此參數,傳回-1,否則傳回此參數在String中的起始索引。lastIndexOf是從後向前查找

        System.out.println("How are you".indexOf("o"));            // 查找傳回位置

        System.out.println("How are you".indexOf("o", 5));        // 查找傳回位置, 從位置5開始

        System.out.println("How are you".indexOf("z"));            // 沒有查到傳回-1

        System.out.println("How are you".lastIndexOf("o"));        // 查找傳回位置

        System.out.println("How are you".lastIndexOf("o", 5));    // 查找傳回位置, 從位置5開始

        System.out.println("How are you".lastIndexOf("z"));        // 沒有查到傳回-1

        // 根據參數截取字元串

        System.out.println("Hello World".substring(6));            // 從位置6開始截取

        System.out.println("Hello World".substring(0, 5));        // 截取0~5個位置的内容

        // 按照指定字元拆分字元串

        String[] s = "[email protected]".split("@");

        for (int i = 0; i < s.length; i++) {

            System.out.println(s[i]);

        // 去除左右空格

        System.out.println("    Night       ".trim());            // 去除左右空格輸出

        // 轉換大小寫

        System.out.println("China".toLowerCase());

        System.out.println("China".toUpperCase());

        // 判斷是否以指定的字元串開頭或結尾

        if ("**NAME".startsWith("**")) {

            System.out.println("**NAME 以**開頭");

        if ("NAME**".endsWith("**")) {

            System.out.println("NAME** 以**結尾");

        // 替換源子字元串為目标子字元串

        System.out.println("good".replaceAll("o", "x"));

StringBuilder類

注意

String類是不可改變的,是以你一旦建立了String對象,那它的值就無法改變了。 如果需要對字元串做很多修改,那麼應該選擇使用StringBuffer & StringBuilder 類。

StringBuilder 類的用法大部分與 String 類相似。

StringBuilder 類的字元串連接配接操作 append() 效率高于 String 類。而且此方法傳回一個 StringBuilder 類的執行個體,這樣就可以采用鍊式方式一直調用 append() 方法。

示例代碼如下:

StringBuilder str = new StringBuilder();

str.append("How ").append("are ").append("you?");

System.out.println(str);

StringBuffer類

StringBuffer 類和 StringBuilder 類大緻相同。

但是 StringBuffer 是線程安全的,是以開銷也更大一些。

參考資料

JAVA 程式設計思想

JAVA 開發實戰經典