目录
一、String类
1. 概述
2. 创建方式
(1)直接赋值
(2)使用new关键字
3. 性能优化
4. 常用方法
(1)==
(2)equals()
(3)concat()
二、StringBuilder类
1. 概述
2. 核心特性
3. 常用方法
(1)append
(2)insert
(3)delete
(4)reverse
(5)toString
4. 性能优化技巧
(1)预设容量(Pre-sizing)
(2)链式调用优化(Method Chaining)
(3)避免循环内重复创建
(4)批量操作替代单个操作
三、StringBuffer类
1. 概述
2. 核心特性
3. 适用场景
四、StringJoiner类
1. 概述
2. 核心特性
3. 基本构造方式
4. 常用方法
(1)add
(2)merge
(3)toString
五、字符串拼接的底层原理
1. 使用+操作符拼接
(1)没有变量(纯字面量拼接)
(2)有变量(涉及变量拼接)
2. 使用String.concat()方法
3. 使用StringBuilder或StringBuffer
Java中的字符串处理类包括String、StringBuilder、StringBuffer和StringJoiner等,它们各自有不同的特性和底层实现原理。
一、String类
 
1. 概述
String类位于java.lang包中,是Java中最基础的字符串类,其底层是一个被final修饰的字符数组char[] value( JDK9及之后,为了节省内存空间,改为使用byte[]数组存储字符 ),这意味着一旦创建,其内容不可更改。这种不可变性使得String在多线程环境下是安全的,但同时也带来了性能开销,因为每次修改都需要创建新的对象。
2. 创建方式
(1)直接赋值
比如 String s = "abc"; 。当使用双引号直接赋值时,系统会检查该字符串在串池中是否存在,如果不存在就创建新的字符串,如果存在就复用。
(2)使用new关键字
 
比如 String s = new String("abc"); 。这种方式会创建新的字符串对象,每new一次就会在堆内存里开辟一块新的空间并创建新的对象,占用额外的内存。
常用构造方法
-  
String():创建一个空字符串。 -  
String(String original):根据传入的字符串创建一个新的字符串对象。 -  
String(char[] value):根据字符数组创建一个新的字符串对象。 
 public static void main(String[] args) {char[] chars = {'a', 'b', 'c', 'd'};String s = new String(chars);System.out.println(s);  // abcd} 
-  
String(byte[] bytes, Charset charset):根据字节数组和指定的字符集创建一个新的字符串对象。 
 public static void main(String[] args) {byte[] bytes = {97, 98, 99, 100};String s = new String(bytes);System.out.println(s);  // abcd} 
3. 性能优化
-  
使用字符串常量池避免重复创建相同字符串。
 -  
避免频繁修改字符串,因为每次修改都会导致新对象的创建。
 
4. 常用方法
(1)==
 
如果是基本数据类型, == 比较的是数据值;如果是引用数据类型, == 比较的是地址值。字符串是引用数据类型,所以比较的是地址值。
 public static void main(String[] args) {String s1 = new String("abc");  // s1记录的是堆里面的地址值String s2 = "abc";  // s2记录的是串池中的地址值System.out.println(s1 == s2);  // false} 
(2)equals()
 
equals() 比较的是字符串内容。如果要忽略大小写的比较,可以使用 equalsIgnoreCase() 。
 public static void main(String[] args) {String s1 = new String("abc");String s2 = "abc";System.out.println(s1.equals(s2));  // true} 
(3)concat()
 
concat() 方法会创建一个新的字符串对象,效率较低。
二、StringBuilder类
 
1. 概述
StringBuilder是可变字符串类(可以看作一个容器),其底层同样是一个字符数组(char[] value),但与String不同的是,它允许动态修改内容,因此比String更高效。
2. 核心特性
-  
可变性(Mutable) :内容可被修改而不产生新对象。
 -  
非线程安全(Not Thread-Safe) :比线程安全的StringBuffer性能更高。
 -  
动态扩容(Dynamic Expansion) :自动增加内部缓冲区容量。
 -  
高效操作(Efficient Operations) :避免频繁内存分配。
 
3. 常用方法
(1)append
 StringBuilder sb = new StringBuilder("abc");// 基本类型追加(自动转换为字符串)sb.append(def)sb.append(123)sb.append(2.5)sb.append(true)// 对象追加(调用toString())sb.append(Object obj)// 子串追加(支持偏移量)sb.append(char[] str, int offset, int len)sb.append(CharSequence s, int start, int end) 
(2)insert
 sb.insert(int offset, boolean b)sb.insert(int offset, char c)sb.insert(int offset, int i)sb.insert(int offset, Object obj) 
(3)delete
 sb.delete(int start, int end)  // 删除[start,end)区间内容  sb.deleteCharAt(int index)  // 删除指定位置字符   
(4)reverse
 sb.reverse()  // 原地反转字符序列   
(5)toString
 String str = sb.toString();  // 转换为不可变字符串 
4. 性能优化技巧
(1)预设容量(Pre-sizing)
 // 预估最终长度设置初始容量  StringBuilder sb=new StringBuilder(1024);  
(2)链式调用优化(Method Chaining)
 sb.append("a").append("b").append("c").reverse().toString(); 
(3)避免循环内重复创建
 // 错误示范(每次循环都新建)for(...){ sb=new StringBuilder(); }// 正确做法(复用同一个)StringBuilder sb=new StringBuilder();for(...){ sb.setLength(0); } 
(4)批量操作替代单个操作
 // 低效方式  for(char c:chars){ sb.append(c); }// 高效方式  sb.append(chars); 
三、StringBuffer类
 
1. 概述
StringBuffer 与 StringBuilder 非常相似,但是其特点是线程安全。因为其方法被 synchronized 修饰,这使得它适用于多线程环境,但因此带来了性能开销。
2. 核心特性
-  
线程安全(Thread-Safe) :所有公开方法都使用
synchronized。 -  
可变性(Mutable) :内容可被修改而不产生新对象。
 -  
动态扩容(Dynamic Expansion) :自动增加内部缓冲区容量。
 -  
兼容性(Compatibility) :从Java1.0开始就存在。
 
3. 适用场景
适用于多线程环境下需要修改字符串的场景。在多线程环境下使用时,可以避免锁竞争问题,但在单线程环境下不如StringBuilder高效。
四、StringJoiner类
 
1. 概述
StringJoiner 是Java8引入的一个专门用于构造由分隔符分隔的字符序列的工具类,它简化了集合元素连接、CSV格式生成等常见场景下的字符串拼接操作。
2. 核心特性
-  
分隔符控制(Delimiter) :可指定固定分隔符连接元素。
 -  
前后缀支持(Prefix/Suffix) :可为结果添加统一的前后缀。
 -  
空值处理(Null Handling) :提供灵活的空元素处理策略。
 -  
链式调用(Fluent API) :支持方法链式调用风格。
 
3. 基本构造方式
 // 仅指定分隔符(无前后缀)new StringJoiner(",")// 完整构造(带前后缀)new StringJoiner(",", "[", "]") 
4. 常用方法
(1)add
 StringJoiner sj = new StringJoiner(",");// 添加单个元素(支持任意CharSequence)sj.add("A").add("B").add("C");// 添加多个元素的快捷方式(Java8+)List<String> list = Arrays.asList("X","Y","Z");list.forEach(joiner::add); 
(2)merge
 // 合并另一个StringJoiner的内容(忽略其前后缀)StringJoiner sj1 = new StringJoiner(",", "[", "]");StringJoiner sj2 = new StringJoiner(",", "[", "]");sj1.add("A").add("B");sj2.add("X").add("Y");sj1.merge(sj2);System.out.println(sj1);  // 输出:[A,B,X,Y] 
(3)toString
 String str = sj1.toString();System.out.println(str);  // 输出:[A,B,X,Y] 
五、字符串拼接的底层原理
1. 使用+操作符拼接
(1)没有变量(纯字面量拼接)
当拼接的内容全部是字符串字面量时,Java编译器会在编译阶段直接将其优化为一个常量字符串,优化后的字符串会被存储在字符串常量池中,避免运行时创建额外的对象。
 String result = "Hello" + "World";// 上述代码会被编译器优化为:String result = "HelloWorld"; 
性能特点:
-  
高效:由于编译期优化,运行时无需创建StringBuilder对象,性能最佳。
 -  
内存节省:字符串直接存储在常量池中,减少内存开销。
 
(2)有变量(涉及变量拼接)
当拼接的内容包括变量时:JDK8以前,系统底层会创建一个StringBuilder对象,依次调用append()方法将每个字符串片段添加到StringBuilder对象中,然后调用toString()方法将StringBuilder对象转换为String对象,而toString()方法的底层是直接new了一个字符串对象。JDK8及以后,系统会预估字符串拼接之后的总大小,把要拼接的内容都放在数组里,本质上也是产生了一个新的字符串。
 String str1 = "Hello";String str2 = "World";String result = str1 + str2;// 上述代码会被编译器转换为:String str1 = "Hello";String str2 = "World";String result = new StringBuilder().append(str1).append(str2).toString(); 
性能特点:
-  
运行时开销:每次拼接都会创建StringBuilder对象,增加运行时开销。
 -  
内存开销:生成的字符串存储在堆内存中,而不是常量池中。
 
2. 使用String.concat()方法
String.concat()方法用于将指定字符串连接到此字符串的末尾。它实际上是通过创建一个新的字符数组,将两个字符串的内容复制到新数组中,然后构造一个新的String对象。
性能特点:
- concat()方法每次调用都会创建一个新的String对象,因此在频繁拼接字符串时性能较差,适用于少量字符串的拼接。
 
3. 使用StringBuilder或StringBuffer
StringBuilder和StringBuffer都提供了可变的字符序列,允许对字符串内容进行修改而不需要创建新的对象。执行流程:创建一个StringBuilder或StringBuffer对象,调用append()方法将每个字符串片段添加到对象中,调用toString()方法将对象转换为String对象。
性能特点:
-  
StringBuilder是非线程安全的,但性能较高。StringBuffer是线程安全的,但性能稍低(因为添加了同步机制)。
 -  
在需要频繁拼接字符串的场景中,使用StringBuilder或StringBuffer可以显著提高性能。
 -  
StringBuilder适用于单线程环境,而StringBuffer适用于多线程环境。
 
