Java字符串API:String/StringBuffer/StringBuilder详解

🏠个人主页:黎雁

🎬作者简介:C/C++/JAVA后端开发学习者

❄️个人专栏:C语言数据结构(C语言)EasyXJAVA游戏规划程序人生

✨ 从来绝巘须孤往,万里同尘即玉京

文章目录

  • Java字符串API:String/StringBuffer/StringBuilder详解
    • [📝 文章摘要](#📝 文章摘要)
    • [一、字符串核心基础:底层存储与不可变性 📖](#一、字符串核心基础:底层存储与不可变性 📖)
      • [1.1 `String`类的不可变性定义](#1.1 String类的不可变性定义)
      • [1.2 `String`不可变性的底层实现(JDK8)](#1.2 String不可变性的底层实现(JDK8))
      • [1.3 不可变性的实际体现:操作会创建新对象](#1.3 不可变性的实际体现:操作会创建新对象)
      • [1.4 `String`不可变性的设计优势](#1.4 String不可变性的设计优势)
    • [二、字符串常量池:String的内存优化机制 🧠](#二、字符串常量池:String的内存优化机制 🧠)
      • [2.1 字符串常量池的核心原理](#2.1 字符串常量池的核心原理)
      • [2.2 `String`的两种创建方式:常量池vs堆内存](#2.2 String的两种创建方式:常量池vs堆内存)
        • [方式1:直接赋值(`String s = "Java"`)→ 常量池](#方式1:直接赋值(String s = "Java")→ 常量池)
        • [方式2:`new`关键字创建(`String s = new String("Java")`)→ 堆内存](#方式2:new关键字创建(String s = new String("Java"))→ 堆内存)
        • 方式3:手动入池(`intern()`方法)
    • [三、三大字符串类核心对比:可变性+线程安全+效率 🆚](#三、三大字符串类核心对比:可变性+线程安全+效率 🆚)
      • [3.1 核心对比表(必记)](#3.1 核心对比表(必记))
      • [3.2 核心设计差异:可变性的实现](#3.2 核心设计差异:可变性的实现)
      • [3.3 自动扩容机制](#3.3 自动扩容机制)
      • [3.4 线程安全性的实现](#3.4 线程安全性的实现)
    • [四、三大字符串类常用方法实战:拼接/截取/替换/查找 📦](#四、三大字符串类常用方法实战:拼接/截取/替换/查找 📦)
      • [4.1 核心拼接方法:`append()`(Buffer/Builder)/`+`(String)](#4.1 核心拼接方法:append()(Buffer/Builder)/+(String))
        • [`String`:`+` 拼接(底层自动优化为StringBuilder)](#String+ 拼接(底层自动优化为StringBuilder))
        • [`StringBuffer`/`StringBuilder`:`append()` 拼接(核心方法)](#StringBuffer/StringBuilderappend() 拼接(核心方法))
      • [4.2 `String`类常用核心方法(开发高频)](#4.2 String类常用核心方法(开发高频))
        • [🔍 查找相关](#🔍 查找相关)
        • [✂️ 截取/分割](#✂️ 截取/分割)
        • [✏️ 替换/修改](#✏️ 替换/修改)
        • [📌 判断相关](#📌 判断相关)
        • [📏 长度/转换](#📏 长度/转换)
      • [4.3 实战案例:String类常用方法综合使用](#4.3 实战案例:String类常用方法综合使用)
      • [4.4 `StringBuffer`/`StringBuilder`特有方法](#4.4 StringBuffer/StringBuilder特有方法)
    • 五、实战场景:如何选择三大字符串类?🌟
    • [六、高频误区&避坑指南 ⚠️](#六、高频误区&避坑指南 ⚠️)
    • [七、JDK9+字符串底层优化:`char\[\]` → `byte\[\]` 🚀](#七、JDK9+字符串底层优化:char[]byte[] 🚀)
      • [7.1 优化原因](#7.1 优化原因)
      • [7.2 优化后的底层源码(JDK9+)](#7.2 优化后的底层源码(JDK9+))
      • [7.3 优化效果](#7.3 优化效果)
    • [✍️ 写在最后](#✍️ 写在最后)

Java字符串API:String/StringBuffer/StringBuilder详解

知识回顾

上一篇我们吃透了Java所有类的根父类------Object类,掌握了toString()equals()hashCode()等核心方法的重写规则与实战用法,理清了==equals()的区别、equals()hashCode()的绑定约定,夯实了Java核心API的基础。本篇我们将学习Java开发中使用频率最高的API------字符串相关类 ,包括StringStringBufferStringBuilder三个核心类。我们会从字符串的底层存储、类的特性入手,逐一讲解三者的核心区别、常用方法,结合实战案例展示各自的使用场景,帮你掌握字符串的正确使用技巧,避免开发中的常见坑🚀!

📝 文章摘要

  • 核心摘要 :本文讲解Java字符串三大核心类StringStringBufferStringBuilder的底层实现、类的特性,深入剖析三者的可变性、线程安全性、执行效率核心区别,拆解字符串的常用操作方法(拼接、截取、替换、查找等),结合实战案例展示不同场景下的类选择策略,同时梳理字符串开发中的常见误区与优化技巧,让你能根据业务场景精准选择字符串类,写出高效、规范的字符串代码。
  • 阅读时长:10分钟
  • 适合人群&阅读重点
    🎯 Java初学者:重点牢记三者的核心区别,掌握String类的常用方法,理解可变性与不可变性的差异。
    📚 高校计算机专业学生:理清字符串的底层字符数组存储机制,理解String的不可变性设计原理,掌握字符串常量池的工作机制。
    💻 初级开发工程师:根据业务场景(单线程/多线程、频繁拼接/少量拼接)选择合适的字符串类,优化字符串拼接的执行效率,避免内存浪费。
    📖 面试备考者:熟记三者的可变性、线程安全性、执行效率区别,理解字符串常量池的作用,应对"String为什么是不可变的""StringBuffer与StringBuilder的区别"类高频面试题。

一、字符串核心基础:底层存储与不可变性 📖

Java中的字符串本质上是字符序列的封装 ,底层基于char[]字符数组(JDK9+后改为byte[]字节数组,节省内存)实现,而String类的不可变性是整个字符串体系的核心,也是理解三个类区别的关键。

1.1 String类的不可变性定义

String类是不可变类(Immutable Class) ,即一旦一个String对象被创建,其底层字符数组的内容和长度就无法被修改 ,任何对字符串的操作(如拼接、截取、替换)都不会修改原对象,而是创建一个新的String对象并返回。

1.2 String不可变性的底层实现(JDK8)

String类的不可变性由其底层源码的三个关键设计保证,这是面试高频考点:

java 复制代码
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    // 1. 字符数组用private final修饰,私有且不可被重新赋值
    private final char value[];
    // 2. 哈希码缓存,private修饰
    private int hash; // Default to 0
    // 3. 无任何修改value数组的公共方法
}
三大设计保证不可变性
  1. 类用final修饰String类被final修饰,无法被继承,避免子类重写方法破坏不可变性;
  2. 字符数组用private final修饰value[]是私有成员,外部无法直接访问,且final修饰使其引用地址无法被重新赋值(注意:final仅保证引用不变,不保证数组内容不变,只是String类未提供修改数组内容的方法);
  3. 无修改数组的公共方法String类仅提供获取字符数组内容的方法(如charAt()),未提供任何修改value[]数组内容的公共方法,底层数组无法被修改。

1.3 不可变性的实际体现:操作会创建新对象

String对象的任何操作都不会修改原对象,而是生成新对象,这是开发中必须注意的点:

java 复制代码
public class TestStringImmutable {
    public static void main(String[] args) {
        String s1 = "Java";
        // 拼接操作:创建新对象,s1仍指向原"Java"
        String s2 = s1 + "EE";
        // 替换操作:创建新对象,s1仍指向原"Java"
        String s3 = s1.replace('J', 'j');

        System.out.println(s1); // Java(原对象未变)
        System.out.println(s2); // JavaEE(新对象)
        System.out.println(s3); // java(新对象)
        System.out.println(s1 == s2); // false(不同对象)
    }
}

1.4 String不可变性的设计优势

String的不可变性并非设计缺陷,而是Java的刻意设计,带来了三大核心优势:

  1. 线程安全:不可变对象的内容不会被修改,多线程环境下无需加锁,天然线程安全;
  2. 支持字符串常量池:不可变性保证了字符串常量池的实现(相同字符串仅存一份),大幅节省内存;
  3. 哈希码缓存String对象的哈希码计算后会被缓存(hash属性),无需重复计算,提升HashMapHashSet等集合的查找效率。

二、字符串常量池:String的内存优化机制 🧠

字符串常量池(String Pool)是JVM为优化字符串内存占用设计的内存区域 (属于方法区/元空间),核心作用是缓存字符串对象,避免重复创建 ,这是String类特有的优化,也是理解String创建方式的关键。

2.1 字符串常量池的核心原理

当创建字符串时,JVM会先在字符串常量池中查找是否存在内容相同的字符串对象

  • 若存在,直接返回常量池中该对象的引用,不创建新对象;
  • 若不存在,在常量池中创建该字符串对象,再返回其引用。

2.2 String的两种创建方式:常量池vs堆内存

String有两种创建方式,对应不同的内存存储位置,也是面试高频考点,核心区别在于是否使用new关键字

方式1:直接赋值(String s = "Java")→ 常量池
java 复制代码
String s1 = "Java";
String s2 = "Java";
System.out.println(s1 == s2); // true(指向常量池同一个对象)

执行流程

  1. JVM在字符串常量池中查找是否有"Java"对象;
  2. 若无,在常量池中创建"Java"对象,将引用赋值给s1
  3. 创建s2时,常量池中已存在"Java",直接将引用赋值给s2s1s2指向同一个对象。
方式2:new关键字创建(String s = new String("Java"))→ 堆内存
java 复制代码
String s1 = new String("Java");
String s2 = new String("Java");
System.out.println(s1 == s2); // false(指向堆中不同对象)

执行流程

  1. JVM先在常量池中查找是否有"Java",若无则创建(步骤1);
  2. 堆内存 中创建一个新的String对象,将常量池中"Java"的字符数组复制到该对象;
  3. 将堆中对象的引用赋值给s1,每次new都会在堆中创建新对象,因此s1s2指向不同对象。

💡 核心结论:==判断字符串是否相等时,仅直接赋值的相同字符串会返回true,new创建的字符串即使内容相同,==也返回false ,判断字符串内容相等必须使用equals()方法

方式3:手动入池(intern()方法)

intern()方法可将堆中 的String对象手动加入字符串常量池,返回常量池中的引用:

java 复制代码
String s1 = new String("Java").intern();
String s2 = "Java";
System.out.println(s1 == s2); // true(s1指向常量池对象)

三、三大字符串类核心对比:可变性+线程安全+效率 🆚

StringBufferStringBuilder是为了解决String频繁拼接时创建大量新对象、效率低下 的问题而设计的,三者的核心区别集中在可变性、线程安全性、执行效率三个维度,这是必须牢记的核心知识点,也是面试必考内容。

3.1 核心对比表(必记)

对比维度 String StringBuffer StringBuilder
可变性 ❌ 不可变(创建新对象) ✅ 可变(修改原对象) ✅ 可变(修改原对象)
线程安全性 ✅ 天然线程安全(不可变) ✅ 线程安全(方法加synchronized) ❌ 非线程安全(方法无锁)
执行效率 最低(频繁拼接创建新对象) 中等(加锁有性能损耗) 最高(无锁,单线程最优)
底层实现 char[]/byte[] char[]/byte[](可扩容) char[]/byte[](可扩容)
初始化容量 固定(字符数组长度不变) 初始容量16,自动扩容 初始容量16,自动扩容
适用场景 少量字符串操作、常量定义 多线程环境、频繁字符串操作 单线程环境、频繁字符串操作

3.2 核心设计差异:可变性的实现

StringBufferStringBuilder可变性 体现在底层字符数组可扩容、可修改 ,且两者都继承自AbstractStringBuilder,底层实现基本一致:

java 复制代码
// AbstractStringBuilder核心源码(可变性实现)
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    char[] value; // 无final修饰,可修改引用和内容
    int count; // 实际存储的字符数
    // 提供append()、insert()、delete()等修改方法,直接修改value数组
}
// StringBuffer继承AbstractStringBuilder,方法加synchronized
public final class StringBuffer extends AbstractStringBuilder implements Serializable, CharSequence {
    @Override
    public synchronized StringBuffer append(String str) {
        super.append(str);
        return this;
    }
}
// StringBuilder继承AbstractStringBuilder,方法无锁
public final class StringBuilder extends AbstractStringBuilder implements Serializable, CharSequence {
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;
    }
}
可变性核心原因

两者的底层value[]字符数组无final修饰 ,且类中提供了append()delete()replace()直接修改字符数组的方法,操作时不会创建新对象,而是直接修改原对象的数组,因此是可变的。

3.3 自动扩容机制

StringBufferStringBuilder的初始容量为16个字符 ,当拼接的字符数超过当前数组长度时,会自动触发扩容 ,扩容规则为:
新容量 = 原容量 * 2 + 2 ,并将原数组的内容复制到新数组中。

💡 开发技巧:若已知字符串拼接的大致长度,可在创建时指定初始容量 (如new StringBuilder(100)),避免频繁扩容带来的数组复制性能损耗。

3.4 线程安全性的实现

  • StringBuffer所有公共方法 都被synchronized关键字修饰,保证多线程环境下的方法执行原子性,因此线程安全,但加锁和释放锁会带来一定的性能损耗;
  • StringBuilder的方法无任何同步修饰 ,执行效率更高,但多线程环境下同时修改会导致数据错乱,因此仅适用于单线程。

四、三大字符串类常用方法实战:拼接/截取/替换/查找 📦

字符串的核心操作包括拼接、截取、替换、查找、比较、转换 等,其中String类提供了最丰富的方法,StringBufferStringBuilder的核心方法为拼接相关(因设计初衷是解决拼接效率问题),且三者的方法名基本一致,便于记忆。

4.1 核心拼接方法:append()(Buffer/Builder)/+(String)

String+ 拼接(底层自动优化为StringBuilder)
java 复制代码
String s = "Java" + "EE" + "MySQL";
// 编译期优化:直接合并为"JavaEEMySQL",仅创建一个对象
String s1 = "JavaEE";
String s2 = s1 + "MySQL";
// 运行期拼接:底层自动创建StringBuilder,执行append()后转String

💡 注意:循环中使用String的+拼接会创建大量StringBuilder和String对象,效率极低,严禁使用!

StringBuffer/StringBuilderappend() 拼接(核心方法)

支持拼接任意数据类型(String、int、char、对象等),直接修改原对象,返回this(可链式调用):

java 复制代码
// 单线程推荐StringBuilder,指定初始容量优化性能
StringBuilder sb = new StringBuilder(20);
sb.append("Java")
  .append(8)
  .append(" ")
  .append(true);
System.out.println(sb.toString()); // Java8 true(转String)

// 多线程使用StringBuffer
StringBuffer sbf = new StringBuffer();
sbf.append("Java").append("EE");
System.out.println(sbf.toString()); // JavaEE

4.2 String类常用核心方法(开发高频)

String类提供了大量字符串操作方法,以下是开发中最常用的,按功能分类整理,便于记忆:

🔍 查找相关
  • char charAt(int index):获取指定索引的字符(索引从0开始);
  • int indexOf(String str):查找子串第一次出现的索引,无则返回-1;
  • int lastIndexOf(String str):查找子串最后一次出现的索引,无则返回-1;
  • boolean contains(CharSequence s):判断是否包含指定子串。
✂️ 截取/分割
  • String substring(int beginIndex):从指定索引截取到末尾;
  • String substring(int beginIndex, int endIndex):截取[beginIndex, endIndex)区间的子串(左闭右开);
  • String[] split(String regex):按指定正则分割字符串,返回字符串数组。
✏️ 替换/修改
  • String replace(CharSequence target, CharSequence replacement):替换所有指定子串;
  • String replaceFirst(String regex, String replacement):替换第一个匹配的子串;
  • String toUpperCase():转为大写;
  • String toLowerCase():转为小写;
  • String trim():去除首尾空格(JDK11+用strip(),支持全角空格)。
📌 判断相关
  • boolean equals(Object anObject):判断内容是否相等(必用);
  • boolean equalsIgnoreCase(String anotherString):忽略大小写判断内容相等;
  • boolean isEmpty():判断是否为空字符串(长度为0);
  • boolean startsWith(String prefix):判断是否以指定前缀开头;
  • boolean endsWith(String suffix):判断是否以指定后缀结尾。
📏 长度/转换
  • int length():获取字符串长度;
  • byte[] getBytes():转为字节数组;
  • char[] toCharArray():转为字符数组;
  • static String valueOf(Object obj):将任意对象转为字符串(万能方法,避免空指针)。

4.3 实战案例:String类常用方法综合使用

java 复制代码
public class TestStringMethod {
    public static void main(String[] args) {
        String s = "  JavaEE&MySQL&Redis  ";

        // 去除首尾空格
        String s1 = s.trim();
        System.out.println(s1); // JavaEE&MySQL&Redis

        // 分割字符串
        String[] arr = s1.split("&");
        for (String str : arr) {
            System.out.println(str); // JavaEE、MySQL、Redis
        }

        // 查找索引
        System.out.println(s1.indexOf("MySQL")); // 6
        System.out.println(s1.contains("Redis")); // true

        // 截取子串
        System.out.println(s1.substring(0, 5)); // JavaE

        // 替换
        System.out.println(s1.replace("&", "|")); // JavaEE|MySQL|Redis

        // 转为小写
        System.out.println(s1.toLowerCase()); // javaee&mysql&redis

        // 任意对象转字符串
        int num = 100;
        System.out.println(String.valueOf(num)); // 100
    }
}

4.4 StringBuffer/StringBuilder特有方法

除了继承AbstractStringBuilderappend(),两者还提供了常用的修改方法,支持链式调用:

  • delete(int start, int end):删除[start, end)区间的字符;
  • insert(int offset, 任意类型):在指定索引插入任意类型数据;
  • reverse():反转字符串;
  • setCharAt(int index, char ch):修改指定索引的字符;
  • toString():转为String对象(最终结果需转String使用)。
实战案例:StringBuilder常用方法
java 复制代码
public class TestStringBuilder {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder("Java");
        // 追加
        sb.append("EE"); // JavaEE
        // 插入
        sb.insert(4, "8"); // Java8EE
        // 反转
        sb.reverse(); // EE8avaJ
        // 删除
        sb.delete(0, 2); // 8avaJ
        // 修改指定索引字符
        sb.setCharAt(0, '9'); // 9avaJ
        // 转String
        String s = sb.toString();
        System.out.println(s); // 9avaJ
    }
}

五、实战场景:如何选择三大字符串类?🌟

开发中选择哪个字符串类,核心依据是两个场景条件是否频繁进行字符串修改(拼接/删除/插入) + 是否在多线程环境下使用,遵循以下原则可保证代码的效率和安全性:

5.1 选择String的场景

推荐场景

  1. 字符串无需修改,仅做常量定义、存储、传递(如配置项、固定文本);
  2. 字符串操作次数极少(如少量的拼接、截取,非循环操作);
  3. 多线程环境下的字符串常量使用(天然线程安全)。

禁止场景:循环中进行字符串拼接(会创建大量对象,效率极低)。

5.2 选择StringBuilder的场景

推荐场景

  1. 单线程环境 下的频繁字符串修改(拼接、删除、插入),如循环拼接、动态拼接字符串;
  2. 性能要求高的场景(无锁,执行效率最高)。
    💡 开发首选 :单线程下的字符串动态操作,优先使用StringBuilder ,并建议指定初始容量(避免频繁扩容)。

5.3 选择StringBuffer的场景

推荐场景

  1. 多线程环境 下的频繁字符串修改,如多线程日志拼接、多线程动态生成字符串;
  2. 要求线程安全,允许轻微性能损耗的场景。

禁止场景:单线程环境下使用(无意义的性能损耗,不如用StringBuilder)。

5.4 经典实战案例:循环拼接字符串的优化

反例:String循环拼接(效率极低,严禁使用)
java 复制代码
String s = "";
for (int i = 0; i < 10000; i++) {
    s += i; // 每次创建新StringBuilder和String对象
}
正例:StringBuilder循环拼接(单线程,指定初始容量)
java 复制代码
StringBuilder sb = new StringBuilder(10000); // 指定初始容量
for (int i = 0; i < 10000; i++) {
    sb.append(i); // 直接修改原对象,无新对象创建
}
String s = sb.toString();
正例:StringBuffer循环拼接(多线程)
java 复制代码
StringBuffer sbf = new StringBuffer(10000);
// 多线程拼接,如线程池执行
ExecutorService pool = Executors.newFixedThreadPool(5);
for (int i = 0; i < 5; i++) {
    pool.submit(() -> {
        sbf.append("test").append("|");
    });
}
pool.shutdown();
System.out.println(sbf.toString());

六、高频误区&避坑指南 ⚠️

字符串开发中的误区多集中在不可变性、==equals()使用、常量池、拼接优化等方面,避开这些坑能大幅提升代码的正确性和效率:

误区1:用==判断字符串内容是否相等

❌ 错误示例:

java 复制代码
String s1 = new String("Java");
String s2 = new String("Java");
if (s1 == s2) { ... } // false,错误判断内容

✅ 正确做法:判断字符串内容相等,必须使用equals()方法==仅能判断引用是否指向同一个对象。

误区2:循环中使用String+拼接字符串

❌ 错误后果:创建大量StringBuilderString对象,占用内存,触发频繁GC,效率极低;

✅ 正确做法:单线程用StringBuilder,多线程用StringBuffer,并指定初始容量。

误区3:认为String+拼接永远效率低

❌ 错误认知:所有String拼接都效率低;

✅ 正确结论:编译期常量拼接 (如"Java"+"EE")会被JVM直接合并为一个字符串,无性能损耗,仅运行期拼接(如变量+常量)才会创建新对象。

误区4:忽略StringBuffer/StringBuilder的初始容量

❌ 错误做法:默认无参构造(初始容量16),频繁拼接导致多次扩容;

✅ 正确做法:已知拼接长度时,指定初始容量 ,避免数组复制的性能损耗,如new StringBuilder(100)

误区5:认为Stringtrim()能去除所有空格

❌ 错误认知:trim()能去除所有空格;

✅ 正确结论:trim()仅能去除首尾的ASCII空格 (\u0020),无法去除全角空格、制表符等;JDK11+推荐使用strip()(去除所有空白字符)、stripLeading()(去除首部空白)、stripTrailing()(去除尾部空白)。

误区6:空指针异常:调用null字符串的方法

❌ 错误示例:

java 复制代码
String s = null;
if (s.equals("Java")) { ... } // 抛出NullPointerException

✅ 正确做法:将常量写在前面 ,或使用Objects.equals()

java 复制代码
// 方式1:常量在前
if ("Java".equals(s)) { ... }
// 方式2:使用Objects.equals()(推荐)
if (Objects.equals(s, "Java")) { ... }

误区7:混淆length()size()

❌ 错误示例:String s = "Java"; s.size();(报错);

✅ 正确结论:字符串获取长度用length()方法 ,集合(List/Set/Map)获取长度用size()方法,数组获取长度用数组名.length(属性)。

七、JDK9+字符串底层优化:char[]byte[] 🚀

JDK9对StringStringBufferStringBuilder的底层实现进行了优化,将**char[]字符数组改为 byte[]字节数组**,并增加了一个coder属性(编码标识),核心目的是节省内存空间

7.1 优化原因

char[]中每个字符占2个字节 (UTF-16编码),但实际开发中,大部分字符串都是拉丁字符 (如英文字母、数字),仅需1个字节(ISO-8859-1/UTF-8)即可存储,使用char[]会造成50%的内存浪费。

7.2 优化后的底层源码(JDK9+)

java 复制代码
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    private final byte[] value; // 改为byte[]
    private final byte coder; // 编码标识:0=Latin1(1字节),1=UTF16(2字节)
    private int hash; // 哈希码缓存
}

7.3 优化效果

  • 拉丁字符(英文字母、数字):用Latin1编码,每个字符占1字节,内存占用减少50%;
  • 非拉丁字符(中文、日文):用UTF16编码,每个字符占2字节,与原char[]一致,无内存变化。
    💡 该优化对开发无感知,所有字符串方法的使用方式不变,仅底层存储优化,提升了内存利用率。

✍️ 写在最后

  1. Java字符串三大核心类为StringStringBufferStringBuilder,核心区别在于可变性、线程安全性、执行效率String不可变、天然线程安全、效率最低,StringBuilder可变、非线程安全、效率最高,StringBuffer可变、线程安全、效率中等;
  2. String的不可变性由final类、private final char[]、无修改方法三大设计保证,其不可变性支撑了字符串常量池和哈希码缓存;
  3. 字符串常量池是JVM的内存优化机制,直接赋值的字符串存在常量池,new创建的字符串存在堆内存,判断内容相等必须用equals()
  4. 开发中类选择原则:少量操作/常量用String,单线程频繁操作用StringBuilder(指定初始容量),多线程频繁操作用StringBuffer
  5. 避坑关键:禁止循环中用String+拼接,用equals()判断内容,常量在前避免空指针,JDK11+用strip()替代trim()

字符串是Java开发中最基础、最常用的API,掌握三者的区别和用法是编写高效Java代码的前提。下一篇我们将学习Java包装类与自动装箱/拆箱,讲解8种基本数据类型对应的包装类、自动装箱拆箱的底层原理与实战坑点,完善Java基础数据类型体系💪!


❤️ 我是黎雁,专注Java基础与实战分享,关注我,一起从0到1吃透Java!

📚 后续文章预告:《Java包装类:自动装箱/拆箱+底层原理+实战避坑》

💬 评论区交流:你在字符串开发中遇到过哪些空指针或效率问题?或者对String的不可变性还有疑问,欢迎留言讨论~

相关推荐
Scott9999HH3 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔3 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社4 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海4 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖5 小时前
JDK 26 新特性详解
java·开发语言
马优晨6 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区8 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大8 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai8 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说8 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json