当前位置: 首页 > news >正文

面试篇-String、StringBuffer和StringBuilder有什么区别?

* 一、基本概念 * 1. String(字符串) * - Java中最基础的字符串类,位于java.lang包 * - 一旦创建,内容就不能改变(不可变) * - 每次"修改"字符串,实际上是创建了一个新的String对象 * - 原对象依然存在,只是引用指向了新对象 * - 内存开销:频繁修改会产生大量垃圾对象 * * 2. StringBuffer(字符串缓冲区) * - 可变的字符串类,位于java.lang包 * - 线程安全(synchronized修饰),适合多线程环境 * - 效率比String高,但比StringBuilder低(因为线程安全有开销) * * 3. StringBuilder(字符串构建器) * - 可变的字符串类,位于java.lang包 * - 线程不安全,但效率最高 * - JDK 5.0新增,推荐在单线程环境下使用

* 二、核心区别对比 * ┌─────────────┬──────────────┬──────────────┬──────────────┐ * │ 对比项 │ String │ StringBuffer │ StringBuilder│ * ├─────────────┼──────────────┼──────────────┼──────────────┤ * │ 可变性 │ 不可变 │ 可变 │ 可变 │ * │ 线程安全 │ 安全(不可变)│ 安全 │ 不安全 │ * │ 效率 │ 低(频繁创建)│ 中 │ 高 │ * │ 适用场景 │ 少量字符串 │ 多线程 │ 单线程 │ * │ 底层实现 │ char[] │ char[] │ char[] │ * │ introduced │ JDK 1.0 │ JDK 1.0 │ JDK 5.0 │ * └─────────────┴──────────────┴──────────────┴──────────────┘

* 三、为什么String不可变? * 1. 字符串常量池优化:相同内容的字符串只存一份,节省内存 * 2. 安全性:不可变对象天生线程安全,适合做Map的key * 3. 缓存优化:hashCode可以缓存,提高哈希表性能

* 四、使用建议 * 1. 字符串少量操作 → 用 String * 2. 多线程环境下字符串频繁修改 → 用 StringBuffer * 3. 单线程环境下字符串频繁修改 → 用 StringBuilder(推荐)

第一部分:演示String的不可变性

public class StringDemo { public static void main(String[] args) { System.out.println(" String vs StringBuffer vs StringBuilder"); // ========== 第一部分:演示String的不可变性 ========== demoStringImmutable(); } /** * String的不可变性【知识点】 * 1. String对象一旦创建,内容就不能改变 * 2. 看似"修改"字符串,实际是创建了新对象 * 3. 原对象依然存在,只是引用指向了新对象 * 4. 内存开销:频繁修改会产生大量垃圾对象 */ private static void demoStringImmutable() { System.out.println("【第一部分】String的不可变性演示\n"); // 第1步:创建一个String对象 String str = "Hello"; // 在字符串常量池中创建"Hello" System.out.println("1. 初始字符串:" + str); // Hello System.out.println(" 内存地址:" + getAddress(str)); // 0xf6f4d33 // 第2步:执行"拼接"操作 str = str + " World"; // 实际创建了新对象"Hello World" System.out.println("2. 拼接后字符串:" + str); // Hello World System.out.println(" 内存地址:" + getAddress(str)); // 0x3f99bd52 // 第3步:再执行一次"拼接" str = str + "!"; // 又创建了新对象"Hello World!" System.out.println("3. 再次拼接后:" + str); // Hello World! System.out.println(" 内存地址:" + getAddress(str)); // 0x4f023edb } }

说明:
- 每次拼接都创建了新对象,原对象变成垃圾等待回收
- 内存地址每次都变化,证明创建了新对象
- 这就是String效率低的原因!


第二部分:演示StringBuffer的可变性

public class StringDemo { public static void main(String[] args) { System.out.println(" String vs StringBuffer vs StringBuilder"); // ========== 第二部分:演示StringBuffer的可变性 ========== demoStringBuffer(); } /** * 演示StringBuffer的可变性【知识点】 * 1. StringBuffer内部维护一个可变的字符数组 * 2. 修改内容时,直接在原对象上修改,不创建新对象 * 3. 线程安全:方法用synchronized修饰,同一时间只能一个线程访问 * 4. 默认容量16个字符,不够时自动扩容(原容量*2+2) */ private static void demoStringBuffer() { System.out.println("【第二部分】StringBuffer的可变性演示\n"); // 第1步:创建StringBuffer对象 // 知识点:推荐指定初始容量,避免频繁扩容 StringBuffer sb = new StringBuffer("Hello"); System.out.println("1. 初始内容:" + sb); // Hello System.out.println(" 内存地址:" + getAddress(sb)); // 0x3a71f4dd System.out.println(" 容量:" + sb.capacity()); // 默认16+5=21(初始值+字符串长度)// 21 // 第2步:追加内容(在原对象上修改) sb.append(" World"); // 在原对象上追加,不创建新对象 System.out.println("2. 追加后:" + sb); // Hello World System.out.println(" 内存地址:" + getAddress(sb)); // 0x3a71f4dd // 第3步:插入内容 sb.insert(5, " Beautiful"); // 在索引5的位置插入 System.out.println("3. 插入后:" + sb); // Hello Beautiful World // 第4步:删除内容 sb.delete(5, 15); // 删除索引5到14的内容(左闭右开) System.out.println("4. 删除后:" + sb); // Hello World // 第5步:替换内容 sb.replace(0, 5, "Hi"); // 将索引0-4的内容替换为"Hi" System.out.println("5. 替换后:" + sb); // Hi World // 第6步:反转字符串 sb.reverse(); // 反转整个字符串 System.out.println("6. 反转后:" + sb); // dlroW iH }

说明:
- 内存地址始终不变,证明一直在操作同一个对象
- 提供了丰富的操作方法:append / insert / delete / replace / reverse
- 线程安全,但效率略低于StringBuilder


第三部分:演示StringBuilder的可变性

public class StringDemo { public static void main(String[] args) { System.out.println(" String vs StringBuffer vs StringBuilder"); // ========== 第三部分:演示StringBuilder的可变性 ========== demoStringBuilder(); } /** * 演示StringBuilder的可变性【知识点】 * 1. StringBuilder和StringBuffer用法几乎一样 * 2. 主要区别:StringBuilder没有synchronized,线程不安全 * 3. 单线程环境下效率比StringBuffer高10%-15% * 4. JDK 5.0新增,推荐日常使用 */ private static void demoStringBuilder() { System.out.println("【第三部分】StringBuilder的可变性演示\n"); // 创建StringBuilder对象 StringBuilder sbd = new StringBuilder("Hello"); System.out.println("1. 初始内容:" + sbd); // Hello System.out.println(" 内存地址:" + getAddress(sbd)); // 0x85ede7b // 追加内容 sbd.append(" World"); System.out.println("2. 追加后:" + sbd); // Hello World System.out.println(" 内存地址:" + getAddress(sbd)); // 0x85ede7b // 插入内容 sbd.insert(6, " Java"); System.out.println("3. 插入后:" + sbd);// Hello JavaWorld // 删除内容 sbd.delete(6, 11); System.out.println("4. 删除后:" + sbd);// Hello World } }

说明:
- 用法和StringBuffer完全一样
- 单线程环境下优先使用StringBuilder
- 内存地址不变,证明操作的是同一个对象


第四部分:性能对比

public class StringDemo { public static void main(String[] args) { System.out.println(" String vs StringBuffer vs StringBuilder"); // ========== 第四部分:性能对比 ========== performanceComparison(); } /** * 性能对比演示【知识点】 * 1. 循环拼接字符串时,性能差异非常明显 * 2. String:每次拼接创建新对象,O(n²)时间复杂度 * 3. StringBuffer/StringBuilder:原地修改,O(n)时间复杂度 * 4. 10000次循环,String可能耗时几秒,StringBuilder只需几毫秒 */ private static void performanceComparison() { System.out.println("【第四部分】性能对比演示(循环10000次拼接)\n"); int count = 10000; // 测试String long start1 = System.currentTimeMillis(); // 记录开始时间(毫秒) String str = ""; for (int i = 0; i < count; i++) { str += i; // 每次循环都创建新对象 } long end1 = System.currentTimeMillis(); // 记录结束时间 System.out.println("String 耗时:" + (end1 - start1) + "ms");// String 耗时:182ms // 测试StringBuffer long start2 = System.currentTimeMillis(); StringBuffer sb = new StringBuffer(); for (int i = 0; i < count; i++) { sb.append(i); // 原地修改,不创建新对象 } long end2 = System.currentTimeMillis(); System.out.println("StringBuffer 耗时:" + (end2 - start2) + "ms");// StringBuffer 耗时:2ms // 测试StringBuilder long start3 = System.currentTimeMillis(); StringBuilder sbd = new StringBuilder(); for (int i = 0; i < count; i++) { sbd.append(i); // 原地修改,不创建新对象 } long end3 = System.currentTimeMillis(); System.out.println("StringBuilder 耗时:" + (end3 - start3) + "ms");// StringBuilder 耗时:8ms } }

说明:
- String最慢,因为每次拼接都创建新对象
- StringBuffer和StringBuilder快得多
- StringBuilder略快于StringBuffer(无同步开销)
- 循环次数越多,差距越明显!


【第五部分】线程安全说明

1. String - 线程安全
- 不可变对象,多个线程共享不会出问题
- 就像共享一本书,谁都不能改,所以安全

2. StringBuffer - 线程安全
- 方法加了synchronized(同步锁)
- 同一时间只能一个线程操作,像公共厕所只有一个坑位
- 安全但效率低,因为要排队等待

3. StringBuilder - 线程不安全
- 没有同步机制,多个线程同时修改会混乱
- 就像多人同时写一块黑板,字会重叠混乱
- 但单线程下效率最高,推荐日常使用

【使用建议】
- 单线程、字符串频繁修改 → 用 StringBuilder
- 多线程、字符串频繁修改 → 用 StringBuffer
- 字符串不经常修改、作为Map的key → 用 String

* 【实际应用场景】 * 场景1:字符串常量、配置信息、Map的key → 用String * 场景2:循环拼接字符串、SQL拼接、JSON构建 → 用StringBuilder * 场景3:多线程环境下的字符串操作 → 用StringBuffer
http://www.jsqmd.com/news/1050124/

相关文章:

  • 闲置钻石变现避坑!2026 年 6 月上海正规回收机构攻略 - 奢侈品交易观察员
  • 2026河源黄金奢侈品回收靠谱门店TOP5|中检双认证河源源奢汇领衔,附避坑指南 - 生活测评小能手
  • 2026年6月20日郴州金价大跌!最新回收行情+变现时机+靠谱门店排名 - 小仙贝贝
  • 终极网盘下载加速方案:一键解锁八大平台满速下载
  • 网盘直链下载助手:告别限速,九大网盘高速下载完全指南
  • 台州怎么登报?办理流程详解 - 资讯速览
  • 宁波本地买宠避坑指南,附几家宠物店参考 - 园友3800037
  • HeaderEditor插件:修改HTTP请求头绕过Google人机验证
  • ZenStatesDebugTool:AMD锐龙处理器硬件调试的终极解决方案
  • 上海个人证件翻译:2026最新办理流程 - 资讯速览
  • 商河县管道漏水检测本地专家团队指南
  • GESP7级C++考试语法知识(四、哈希表(4、unordered_map)
  • 果速修门店环境与设备配置:无尘维修间+工业级设备链,全国统一标准,热线400-811-2953 - 博客万
  • 2026年6月最新格拉苏蒂中国官方售后电话热线客服地址服务网点 - 亨得利官方服务中心
  • 基于AI视觉的桌面GUI自动化:UI-TARS Desktop原理与实践
  • 思源宋体终极使用指南:7种字重免费开源宋体的完整配置方案
  • 如何高效管理音乐歌词:MusicLyricApp的完整解决方案
  • 走访河源128家黄金奢侈品回收店,这份靠谱商家清单出手前必看 - 生活测评小能手
  • LPC213x UART0寄存器配置、波特率计算与自动波特功能实战解析
  • 2026佛山白蚁防治避坑实测!5大主流平台横向对比本地人防御优选攻略 - 博客万
  • LPC210x ADC与定时器实战:寄存器级配置、避坑指南与协同应用
  • 线段树算法总结
  • 如何高效解决B站缓存视频播放难题:m4s-converter的5个实用技巧
  • 量化特征工程实战:构建工业级Alpha因子生态体系
  • 2026 马鞍山市|全市中考一两百分初三统一招生,淮南职业技术学校公办中职简章公示,联系方式 15756001370 - 我叫小周
  • 电瓶车托运保价别踩坑!2026避坑指南+正确买法 - 快递物流资讯
  • SCF5250微控制器:嵌入式音频系统核心架构与驱动开发实战
  • 2026年杭州本地生活GEO技术革新:如何精准提升用户定位体验
  • 免费网盘直链下载助手终极指南:告别限速,轻松获取高速下载链接
  • YOLO26涨点改进| Arxiv 2026 | 独家频域创新改进篇 | 引入PRM相位校正模块,通过从频率域增强目标表征,助力红外小目标检测、遥感目标检测、图像分割任务高效涨点