Java字符与字符串处理:char、String、StringBuilder与StringBuffer深度解析

# Java字符与字符串处理:char、String、StringBuilder与StringBuffer深度解析


字符与字符串处理是Java编程中最基础也最频繁的操作之一。从单个字符的char类型,到不可变的String,再到可变的StringBuilder和StringBuffer,Java为开发者提供了一套完整的字符序列处理体系。理解这些类的特性与适用场景,是编写高效可靠代码的基础。


## 一、char:字符类型的基础


char是Java的基本数据类型,占用2字节内存,采用Unicode编码,可以表示世界上绝大多数语言的字符。每个char对应一个Unicode码点,取值范围从'\u0000'到'\uffff'(即0到65535)。


```java

char letter = 'A';

char chinese = '中';

char unicode = '\u4e2d'; // 同样是'中'字符

char digit = 65; // ASCII码,对应'A'


// char的运算

char nextChar = (char) (letter + 1); // 'B'

boolean isDigit = Character.isDigit('5'); // true

boolean isLetter = Character.isLetter('A'); // true

```


char类型支持基本的算术运算和比较操作,Character包装类提供了丰富的静态方法用于字符判断和转换。需要注意的是,对于超出BMP(基本多文种平面)范围的罕见字符,需要用两个char(即代理对)来表示。


## 二、String:不可变字符串


String是Java中使用最频繁的类之一,它的核心设计是不可变性——一旦创建,其内容就不能被改变。这种设计带来了线程安全和缓存友好的特性,但也意味着每次修改都会创建新对象。


### 1. 创建与存储


```java

String s1 = "Hello"; // 字符串常量池

String s2 = new String("Hello"); // 堆内存新对象

String s3 = "Hello"; // 复用常量池中的对象

<"ynh.h4k7.org.cn"><"nyr.h4k7.org.cn"><"ytn.h4k7.org.cn">

System.out.println(s1 == s2); // false

System.out.println(s1 == s3); // true

System.out.println(s1.equals(s2)); // true

```


字符串常量池是JVM对String的特殊优化,相同的字符串字面量只会存储一份。使用new String()则会强制在堆中创建新对象,除非必要,否则应优先使用字面量方式。


### 2. 常用操作


```java

String str = "Java Programming";


// 获取信息

int length = str.length();

char firstChar = str.charAt(0);

int index = str.indexOf("Programming");


// 比较与判断

boolean equals = str.equals("Java Programming");

boolean ignoreCase = str.equalsIgnoreCase("java programming");

boolean startsWith = str.startsWith("Java");


// 转换与截取

String upper = str.toUpperCase();

String lower = str.toLowerCase();

String sub = str.substring(5, 9); // "Prog"

String replaced = str.replace("Java", "Python");


// 分割与拼接

String[] parts = str.split(" ");

String joined = String.join("-", "2023", "03", "15");

```


String的每个“修改”操作都会返回新字符串,原字符串保持不变。这种模式在需要频繁修改的场景下会产生大量临时对象,影响性能。


## 三、StringBuilder:可变字符串


StringBuilder是可变字符序列,提供与StringBuffer兼容的API但不保证线程安全。它内部维护一个字符数组,当容量不足时自动扩容。StringBuilder适用于单线程环境下的字符串拼接和修改操作。


### 1. 基本操作


```java

StringBuilder sb = new StringBuilder(); // 默认容量16

StringBuilder sb2 = new StringBuilder("Hello"); // 初始内容


// 追加操作

sb.append("Hello");

sb.append(' ');

sb.append("World");


// 插入操作

sb.insert(5, " Java"); // 在索引5处插入


// 删除操作

sb.delete(5, 10); // 删除索引5到9的字符

sb.deleteCharAt(0); // 删除第一个字符


// 修改与替换

sb.setCharAt(0, 'h');

sb.replace(6, 11, "Earth");


// 反转与转字符串

sb.reverse();

String result = sb.toString();

```


StringBuilder的所有修改操作都返回自身,支持链式调用,代码简洁直观。

<"rtg.h4k7.org.cn"><"dgr.h4k7.org.cn"><"rht.h4k7.org.cn">

### 2. 性能优势


```java

// 低效方式:产生大量临时对象

String result = "";

for (int i = 0; i < 1000; i++) {

    result += i; // 每次循环都创建新String对象

}


// 高效方式:使用StringBuilder

StringBuilder sb = new StringBuilder();

for (int i = 0; i < 1000; i++) {

    sb.append(i);

}

String efficientResult = sb.toString();

```


在循环拼接场景中,StringBuilder比String直接拼接的效率高出几个数量级,内存开销也大幅降低。


## 四、StringBuffer:线程安全可变字符串


StringBuffer与StringBuilder的API几乎完全相同,区别在于StringBuffer的方法使用synchronized关键字修饰,保证了线程安全。


```java

StringBuffer buffer = new StringBuffer();

buffer.append("Thread").append("Safe");

String result = buffer.toString();

```


在多线程环境下共享可变字符串时,StringBuffer是安全的选择。但同步机制带来额外的性能开销,在单线程场景中不如StringBuilder高效。


## 五、四者对比与选择策略


| 类型 | 可变性 | 线程安全 | 性能 | 适用场景 |

|------|--------|----------|------|----------|

| char | 可变(基本类型)| - | 最高 | 单个字符处理 |

| String | 不可变 | 安全 | 中等(读快写慢)| 字符串常量、少量拼接 |

| StringBuilder | 可变 | 不安全 | 高 | 单线程大量修改 |

| StringBuffer | 可变 | 安全 | 中 | 多线程共享修改 |


选择建议:

- 处理单个字符时,使用char类型

- 字符串内容不变或少量修改,使用String

- 单线程环境下频繁修改字符串,使用StringBuilder

- 多线程环境下共享可变字符串,使用StringBuffer


## 六、实际应用示例


以下示例演示了三种字符串类在不同场景下的使用:


```java

// 静态文本使用String

String greeting = "欢迎使用本系统";


// 动态构建SQL语句使用StringBuilder(单线程)

public String buildQuery(String name, Integer age) {

    StringBuilder sql = new StringBuilder("SELECT * FROM users WHERE 1=1");

    if (name != null) {

        sql.append(" AND name = '").append(name).append("'");

    }

    if (age != null) {

        sql.append(" AND age = ").append(age);

    }

    return sql.toString();

}


// 日志收集使用StringBuffer(可能多线程)

public class Logger {

    private StringBuffer logBuffer = new StringBuffer();

    

    public void log(String message) {

        logBuffer.append(System.currentTimeMillis())

                 .append(": ")

                 .append(message)

                 .append("\n");

    }

    

    public String getLogs() {

        return logBuffer.toString();

    }

}

```


理解char、String、StringBuilder和StringBuffer的特性差异,能够帮助开发者在实际项目中做出合理选择,写出既清晰又高效的代码。字符串处理看似基础,但正确选择工具往往能带来显著的性能改善。


请使用浏览器的分享功能分享到微信等