一、核心概念

1. String的本质

  • 不可变性(Immutable):String对象一旦创建,其内容不可更改。所有看似“修改”的操作(如拼接、替换)都会生成新的String对象。
  • 存储结构
    • JDK 8及以前:private final char[] value
    • JDK 9及以后:private final byte[] value + private final byte coder(编码标记,节省空间)。
  • 字符串常量池:JVM为字符串常量池分配独立内存区域,用于存储字面量创建的String对象(如String s = "hello"),避免重复创建相同字符串。

2. 创建方式

方式 示例 存储位置
字面量 String s = "hello"; 常量池
构造方法 new String("hello"); 堆内存
字符/字节数组 new String(char[] data) 堆内存
拼接 String s = "he" + "llo"; 常量池(编译期优化)

二、操作步骤

1. 创建字符串

// 字面量创建(推荐)
String str1 = "Hello";

// 构造方法创建
char[] chars = {'H', 'e', 'l', 'l', 'o'};
String str2 = new String(chars); // 输出 "Hello"

// 从字节数组创建(需指定编码)
byte[] bytes = {72, 101, 108, 108, 111};
String str3 = new String(bytes, StandardCharsets.UTF_8); // 输出 "Hello"

2. 字符串连接

  • 使用+操作符(自动调用StringBuilder):
    String result = "Hello, " + "World!"; // 输出 "Hello, World!"
    
  • 使用concat方法
    String result = "Hello".concat(" World!"); // 输出 "Hello World!"
    

3. 字符串比较

  • 比较内容(推荐):
    String s1 = "Hello";
    String s2 = new String("Hello");
    boolean isEqual = s1.equals(s2); // true
    
  • 比较地址(不推荐):
    String s1 = "Hello";
    String s2 = new String("Hello");
    boolean isSame = (s1 == s2); // false(不同对象)
    

4. 获取长度与字符

String str = "Hello";
int length = str.length(); // 5
char firstChar = str.charAt(0); // 'H'

5. 查找与替换

  • 查找子串位置
    int index = "Hello World".indexOf("World"); // 6
    
  • 替换子串
    String newStr = "Hello World".replace("World", "Java"); // "Hello Java"
    

6. 截取与拆分

  • 截取子串
    String sub = "Hello World".substring(6); // "World"
    
  • 按正则拆分
    String[] parts = "apple,banana,orange".split(","); // ["apple", "banana", "orange"]
    

7. 格式化字符串

String formatted = String.format("Number: %d, Text: %s", 123, "Java"); 
// 输出 "Number: 123, Text: Java"

三、常见错误与注意事项

1. 常见错误

  • 错误1:使用==比较内容
    String s1 = "Hello";
    String s2 = new String("Hello");
    if (s1 == s2) { ... } // 错误!应使用equals()
    
  • 错误2:频繁修改字符串导致性能问题
    String result = "";
    for (int i = 0; i < 1000; i++) {
        result += i; // 每次循环生成新对象,性能差
    }
    

2. 注意事项

  • 字符串常量池特性
    • String s = "hello"; 会检查常量池是否存在相同值,存在则复用。
    • new String("hello"); 始终在堆中创建新对象。
  • 不可变性影响
    String s = "Hello";
    s.concat(" World"); // 原s仍为"Hello",新对象为"Hello World"
    

四、使用技巧

1. 快速判断字符串

  • 空值检查
    if (str == null || str.isEmpty()) { ... }
    
  • 前后缀匹配
    if (str.startsWith("http://")) { ... }
    if (str.endsWith(".txt")) { ... }
    

2. 大小写转换

String upper = "hello".toUpperCase(); // "HELLO"
String lower = "HELLO".toLowerCase(); // "hello"

3. 去除空格与修剪

String trimmed = "  Java  ".trim(); // "Java"

五、最佳实践与性能优化

1. 频繁修改用StringBuilder

StringBuilder sb = new StringBuilder();
for (int i = 0; i < 1000; i++) {
    sb.append(i);
}
String result = sb.toString(); // 单次生成最终字符串

2. 避免重复创建对象

// 不推荐
String s1 = "Hello" + " " + "World";
String s2 = "Hello " + "World";

// 推荐(合并常量)
String s = "Hello World";

3. 缓存哈希值(适用于自定义类)

  • 若将String作为HashMap的Key,其hashCode会被缓存,提升性能。

4. 使用String.valueOf()转换类型

int num = 123;
String str = String.valueOf(num); // "123"

六、性能对比

操作 String StringBuilder
单次拼接
多次拼接(1000次) ❌(性能差) ✅(高效)

七、总结

  • 优先使用字面量创建字符串,利用常量池优化。
  • 避免使用==比较内容,改用equals()
  • 频繁修改字符串时使用StringBuilder,减少对象创建。
  • 理解不可变性,避免误以为直接修改原字符串。