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的不可变性还有疑问,欢迎留言讨论~

相关推荐
山枕檀痕2 小时前
JPA Projection 详解(接口投影 / 类投影 / 动态投影 / 原生SQL映射)
java·hibernate·jpa
上海合宙LuatOS2 小时前
LuatOS socket基础知识和应用开发
开发语言·人工智能·单片机·嵌入式硬件·物联网·开源·php
凯子坚持 c2 小时前
Qt常用控件指南(6)
开发语言·qt
少控科技2 小时前
QT第三个程序 - 表达式计算器
开发语言·qt
轩情吖2 小时前
Qt容器类控件之QGroupBox与QTabWidget
开发语言·c++·qt·qgroupbox·qtabwidget·桌面级开发
helloworldandy2 小时前
C++安全编程指南
开发语言·c++·算法
Jack_abu2 小时前
stream().toList()与.collect(Collectors.toList())
java·stream·jdk8
黎雁·泠崖2 小时前
Java核心API之Object类:所有类的根父类
java·开发语言
Remember_9932 小时前
【LeetCode精选算法】位运算专题
java·开发语言·jvm·后端·算法·leetcode