Java String字符串:創建、拼接與比較,常見問題解決

一、什麼是String?

在Java中,String是用於表示文本數據的類,它是不可變的(一旦創建,內容就無法修改)。正因爲不可變,String在Java中被廣泛用於存儲和處理文本,比如用戶輸入、文件名、URL等。

二、String的創建方式

Java中創建String對象主要有兩種方式,它們的內存行爲不同,初學者容易混淆,需要重點區分。

1. 直接賦值(推薦)
String s1 = "hello";
String s2 = "hello";
  • 原理:Java會先在字符串常量池(一種特殊的內存區域,用於複用相同的字符串常量)中查找是否存在"hello"
  • 如果存在,s1s2直接指向常量池中的同一個"hello"對象。
  • 如果不存在,會在常量池中創建新的"hello",並讓s1/s2指向它。
  • 特點:相同常量會被複用,節省內存。例如,s1s2雖然是兩個變量,但它們的引用相同(s1 == s2true)。
2. new關鍵字創建
String s3 = new String("hello");
String s4 = new String("hello");
  • 原理:無論常量池是否有"hello",都會在堆內存中創建一個新的String對象,內容爲"hello",且新對象的引用與常量池無關。
  • 特點:即使內容相同,s3s4的引用也不同(s3 == s4false)。因爲new會強制新建堆對象,而直接賦值優先複用常量池。
對比直接賦值與new創建
方式 引用是否相同(相同內容) 內存位置 是否複用常量池
直接賦值 true(常量池複用) 常量池
new創建 false(堆中新建) 堆內存 否(但內容相同的常量會先放入常量池)

三、String的拼接操作

拼接字符串是常用操作,Java提供了多種方式,需注意不同方式的性能和結果差異。

1. 使用+號拼接(最直觀)
String a = "a";
String b = "b";
String c = a + b; // 結果:"ab"
  • 原理+號在編譯時會被編譯器優化。
  • 如果拼接的是全常量(如"a" + "b"),會直接在常量池生成"ab"
  • 如果拼接中包含變量(如a + ba/b是變量),會在堆中創建新的String對象。
  • 注意:頻繁用+號拼接(尤其是循環中)會創建大量臨時對象,效率極低!
2. 使用concat()方法
String d = "a".concat("b"); // 結果:"ab"
  • 原理concat()String類的方法,返回拼接後的新字符串,原字符串不變(因爲String不可變)。
  • 示例
  String e = "hello";
  String f = e.concat("world"); // f是"helloworld",e仍爲"hello"
3. 使用StringBuilder/StringBuffer(高效拼接)

String不可變,每次拼接都會新建對象;而StringBuilder/StringBuffer可變的字符序列,拼接時直接修改內部數組,效率更高。
- 區別
- StringBuilder:非線程安全,單線程下效率更高(默認推薦)。
- StringBuffer:線程安全(方法加了synchronized),多線程場景使用。

示例

StringBuilder sb = new StringBuilder();
sb.append("a"); // 拼接單個字符
sb.append("b"); // 拼接字符串
String result = sb.toString(); // 轉換爲String(最終結果)

四、String的比較操作

比較字符串時,==equals()的作用完全不同,初學者常因混淆兩者導致邏輯錯誤。

1. ==:比較對象引用(是否指向同一個對象)
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");

System.out.println(s1 == s2); // true(指向常量池同一個對象)
System.out.println(s1 == s3); // false(s3是堆中新建對象,引用不同)
2. equals():比較字符串內容(忽略引用)
String s1 = "hello";
String s3 = new String("hello");

System.out.println(s1.equals(s3)); // true(內容相同)
  • 注意
  • equals()只能用於非null字符串,否則會拋出NullPointerException(如null.equals("a"))。
  • 避免用==代替equals()比較內容!
3. 正確比較空字符串

判斷字符串是否爲空時,推薦用isEmpty()length() == 0,而非== ""== null

String s = "";
System.out.println(s.isEmpty()); // true(空字符串,但非null)
System.out.println(s.length() == 0); // true
System.out.println(s == ""); // true(內容相同,但不推薦)

五、常見問題與解決方法

1. 混淆==equals()

錯誤場景

String a = new String("hello");
String b = new String("hello");
if (a == b) { // 錯誤!==比較引用,a和b是不同對象
    System.out.println("a和b相同");
} else {
    System.out.println("a和b內容相同但不是同一個對象");
}

解決:用equals()比較內容:

if (a.equals(b)) { // 正確!比較內容
    System.out.println("a和b內容相同");
}
2. 循環中頻繁用+號拼接字符串

錯誤場景

String result = "";
for (int i = 0; i < 1000; i++) {
    result = result + i; // 每次循環新建String對象,效率極低!
}

解決:用StringBuilder替代+號:

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i); // 直接修改內部數組,無額外對象創建
}
String result = sb.toString(); // 最終轉換爲String
3. 空字符串判斷用== ""

錯誤場景

String s = null;
if (s == "") { // 錯誤!null不能用== ""判斷
    System.out.println("空字符串");
}

解決:先判空,再比較內容:

if (s != null && s.isEmpty()) { // 推薦寫法
    System.out.println("空字符串");
}

六、總結

  1. 不可變性String一旦創建無法修改,任何拼接/修改操作都會生成新對象。
  2. 創建方式:直接賦值優先複用常量池,new關鍵字強制新建堆對象。
  3. 拼接選擇:少量拼接用+concat(),大量拼接(如循環)用StringBuilder
  4. 比較規則==比較引用,equals()比較內容,避免混淆;空字符串用isEmpty()length() == 0,並先判null

掌握以上內容,就能避免大部分String相關的常見錯誤,寫出高效清晰的Java代碼。

小夜