Jtoss Jtoss
首页
  • 数据结构与算法

    • 数据结构与算法 - 概述
    • 数据结构与算法 - 复杂度分析
    • 数据结构 - 线性表
    • 算法 - 常见排序算法
  • 代码规范

    • 代码简洁之道
    • 阿里巴巴开发手册
    • 谷歌Java编程风格指南
  • 设计模式

    • 编写高质量代码概述
    • 面向对象
    • 设计原则
    • 设计模式-创建型
    • 设计模式-结构型
    • 设计模式-行为型(上)
    • 设计模式-行为型(下)
    • 浅析框架源码中的设计模式
    • 业务框架实战案例
  • MySQL 基础

    • MySQL - 数据库设计规范
    • MySQL - 必知必会
  • MySQL 进阶

    • MySQL - 基础架构
    • MySQL - InnoDB存储引擎
    • MySQL - InnoDB缓冲池
    • MySQL - 事务与锁
    • MySQL - 索引
    • MySQL - 查询执行计划
    • MySQL - 性能优化
  • Redis 系列

    • Redis入门 - 基础相关
    • Redis进阶 - 数据结构
    • Redis进阶 - 持久化RDB和AOF
    • Redis进阶 - 事件机制
    • Redis进阶 - 事务
    • Redis进阶 - 高可用高可扩展
    • Redis进阶 - 缓存问题
    • Redis进阶 - 性能调优
  • Java 基础

    • Java 基础 - 知识点
    • Java 基础 - 面向对象
    • Java 基础 - Q/A
  • Java 进阶 - 集合框架

    • Java 集合框架详解
  • Java 进阶 - 多线程与并发

    • Java 并发 - 理论基础
    • Java 并发 - 线程基础
    • Java 并发 - 各种锁
    • Java 并发 - 关键字 volatile
    • Java 并发 - 关键字 synchronized
    • JUC - CAS与原子操作
    • JUC - 锁核心类AQS
    • JUC - 锁接口和类简介
    • JUC - 并发容器简介
    • JUC - 通信工具类
    • JUC - Fork-Join框架
    • JUC - 线程池
  • Java 进阶 - JVM

    • JVM - 概述
    • JVM - 类加载机制
    • JVM - 内存结构
    • JVM - 垃圾回收机制
    • JVM - 性能调优
  • Maven系列

    • Maven基础知识
    • Maven项目构建
    • Maven多模块配置
  • Spring 框架

    • Spring 框架 - 框架介绍
    • Spring 框架 - IOC详解
    • Spring 框架 - AOP详解
    • Spring 框架 - SpringMVC详解
  • Spring Boot 系列

    • Spring Boot - 开发入门
    • Spring Boot - 接口相关
  • Spring Cloud 系列
  • Mybatis 系列

    • Mybatis - 总体框架设计
    • Mybatis - 初始化基本过程
    • Mybatis - sqlSession执行过程
    • Mybatis - 插件机制
    • Mybatis - 事务管理机制
    • Mybatis - 缓存机制
  • 业务常见问题

    • Java 业务开发常见错误(一)
    • Java 业务开发常见错误(二)
    • Java 业务开发常见错误(三)
    • Java 业务开发常见错误(四)
    • Java 业务开发常见错误(五)
    • Java 业务开发常见错误(六)
  • IDEA系列

    • IDEA 2021开发环境配置
    • IDEA 快捷键
  • Git系列

    • git status中文乱码
  • 其他

    • Typora+Picgo 自动上传图片
    • hsdis 和 jitwatch
  • 实用技巧
  • 收藏
  • 摄影
  • 学习
  • 标签
  • 归档

Jason Huang

后端程序猿
首页
  • 数据结构与算法

    • 数据结构与算法 - 概述
    • 数据结构与算法 - 复杂度分析
    • 数据结构 - 线性表
    • 算法 - 常见排序算法
  • 代码规范

    • 代码简洁之道
    • 阿里巴巴开发手册
    • 谷歌Java编程风格指南
  • 设计模式

    • 编写高质量代码概述
    • 面向对象
    • 设计原则
    • 设计模式-创建型
    • 设计模式-结构型
    • 设计模式-行为型(上)
    • 设计模式-行为型(下)
    • 浅析框架源码中的设计模式
    • 业务框架实战案例
  • MySQL 基础

    • MySQL - 数据库设计规范
    • MySQL - 必知必会
  • MySQL 进阶

    • MySQL - 基础架构
    • MySQL - InnoDB存储引擎
    • MySQL - InnoDB缓冲池
    • MySQL - 事务与锁
    • MySQL - 索引
    • MySQL - 查询执行计划
    • MySQL - 性能优化
  • Redis 系列

    • Redis入门 - 基础相关
    • Redis进阶 - 数据结构
    • Redis进阶 - 持久化RDB和AOF
    • Redis进阶 - 事件机制
    • Redis进阶 - 事务
    • Redis进阶 - 高可用高可扩展
    • Redis进阶 - 缓存问题
    • Redis进阶 - 性能调优
  • Java 基础

    • Java 基础 - 知识点
    • Java 基础 - 面向对象
    • Java 基础 - Q/A
  • Java 进阶 - 集合框架

    • Java 集合框架详解
  • Java 进阶 - 多线程与并发

    • Java 并发 - 理论基础
    • Java 并发 - 线程基础
    • Java 并发 - 各种锁
    • Java 并发 - 关键字 volatile
    • Java 并发 - 关键字 synchronized
    • JUC - CAS与原子操作
    • JUC - 锁核心类AQS
    • JUC - 锁接口和类简介
    • JUC - 并发容器简介
    • JUC - 通信工具类
    • JUC - Fork-Join框架
    • JUC - 线程池
  • Java 进阶 - JVM

    • JVM - 概述
    • JVM - 类加载机制
    • JVM - 内存结构
    • JVM - 垃圾回收机制
    • JVM - 性能调优
  • Maven系列

    • Maven基础知识
    • Maven项目构建
    • Maven多模块配置
  • Spring 框架

    • Spring 框架 - 框架介绍
    • Spring 框架 - IOC详解
    • Spring 框架 - AOP详解
    • Spring 框架 - SpringMVC详解
  • Spring Boot 系列

    • Spring Boot - 开发入门
    • Spring Boot - 接口相关
  • Spring Cloud 系列
  • Mybatis 系列

    • Mybatis - 总体框架设计
    • Mybatis - 初始化基本过程
    • Mybatis - sqlSession执行过程
    • Mybatis - 插件机制
    • Mybatis - 事务管理机制
    • Mybatis - 缓存机制
  • 业务常见问题

    • Java 业务开发常见错误(一)
    • Java 业务开发常见错误(二)
    • Java 业务开发常见错误(三)
    • Java 业务开发常见错误(四)
    • Java 业务开发常见错误(五)
    • Java 业务开发常见错误(六)
  • IDEA系列

    • IDEA 2021开发环境配置
    • IDEA 快捷键
  • Git系列

    • git status中文乱码
  • 其他

    • Typora+Picgo 自动上传图片
    • hsdis 和 jitwatch
  • 实用技巧
  • 收藏
  • 摄影
  • 学习
  • 标签
  • 归档
  • Java 基础

    • Java 基础 - 谈谈 Java 平台
    • Java 基础 - 知识点
    • Java 基础 - 面向对象
    • Java 基础 - Q/A
    • 扩展 - int 和 Integer
    • 扩展 - final、finally、finalize
    • 扩展 - String、StringBuilder、StringBuffer
    • 扩展 - Exception 和 Error
    • 扩展 - 引用
    • 扩展 - 数值计算问题
    • 扩展 - 反射和动态代理
  • Java 进阶 - 集合框架

  • Java 进阶 - 多线程与并发

  • Java 进阶 - JVM

  • Java 进阶 - 版本特性

  • Java
  • Java 基础
Jason

扩展 - String、StringBuilder、StringBuffer

# String、StringBuilder、StringBuffer

可变性:

  • String 不可变
  • StringBuilder 和 StringBuffer 可变

线程安全性:

  • String 线程安全
  • StringBuilder 线程不安全
  • StringBuffer 线程安全

String 类是构造和操作字符串的一个类,是典型的 immutable 类,其类、方法、属性都被修饰为 final,原生的支持线程安全。

场景: 由于 String 的不可变性,在对字符串进行操作时,当改变原字符串内容都会产生一个新的字符串对象。而当对字符串使用重载 + 或 += 频繁操作,会产生大量需要垃圾回收的中间对象

String strByConcat = "aa" + "bb";
1

解决方案: StringBuffer 与 StringBuilder 都是为解决 String 在拼接过程中产生过多的中间对象而设计的

String strByBuilder  = new
StringBuilder().append("aa").append("bb").toString();
1
2

它们都继承自 AbstractStringBuilder 类,使用 char 数组存放字符串数据(JDK9 之后使用 byte 数组)。不同之处在与 StringBuffer 是线程安全的,实现方式是在 StringBuilder 修改数据的相关方法前添加 synchronized 关键字,所以 StringBuffer 的性能不如 StringBuilder,如果不存在线程安全问题则推荐使用 StringBuilder 类。

StringBuffer 和 StringBuilder 在构造初始化 char 数组的默认长度是16,如果初始化有输入字符串则长度为 输入字符串长度 + 16,也可以在构造时指定初始化长度,在已知需要拼接的大致长度,通过直接初始化相应长度的 StringBuffer 或 StringBuilder 可以避免多次扩容(每次扩容都需要通过 Arrays.copy() 函数复制并创建新的数组);

扩容规则位:当前长度 x 2 + 2

// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
	newCapacity = minCapacity;
}
1
2
3
4
5

在实际中,以下两种写法的效率是一样的,因为 Java 虚拟机的编译时对代码进行了优化,将通过 + 符号连接的字符串操作编译为 StringBuilder 操作:

String strByConcat = "aa" + "bb";

StringBuilder sb = new StringBuilder();
String strByBuilder  = sb.append("aa").append("bb").toString();
1
2
3
4

通过 javap 反编译结果如下:

stringbuilder

需要注意:在循环体内使用 String 重载 + 或 +=,在每次循环编译器都会创建一个新的 StringBuilder 对象性,为避免这种情况,建议在循环体外自己创建一个 StringBuilder 对象,用来构建最终的结果。

场景:实际应用中一般都存在大量的字符串对象,如果能够减少重复创建相同的字符串,就可以有效降低内存消耗和对象创建开销。

解决方案:

  • 缓存方式:

    而 Java 6 提供 intern() 方法,通过调用该方法将字符串缓存起来(缓存位置为 PermGen 永久代),所以如果大量使用 intern 方法会存在 OOM 的风险故不被推荐使用,而后续版本中缓存位置放在了堆中,避免了永久代被占满的问题,而 Java 8 则把缓存位置放在元数据区 MetaSpace 中,缓存大小也在不断变大。

    在实际运行时为了优化,字符串的一些基础操作会直接利用 JVM 内部的 Intrinsic 机制,往往运行的就是特殊优化的本地代码,而根本就不是 Java 代码生成的字节码。

  • 存储方式:

    在 Java 9 前字符串 String 是通过 char 数组存放的,在 Java 中 char 占用2个byte,实际语言中根本不需要太宽的 char,从而造成一定的浪费。而在 Java 9 对 String 进行了重构,引入 Compact Strings 设计,将字符串数据存储方式由 char 数组改为了 byte 数组。虽然这样导致在同样数组长度下,存储容量降低了一倍,但这种紧凑型字符串带来的是:更小的内存占用,更快的操作速度。

#Java
上次更新: 2024-08-19
扩展 - final、finally、finalize
扩展 - Exception 和 Error

← 扩展 - final、finally、finalize 扩展 - Exception 和 Error→

最近更新
01
开始
01-09
02
AI工具分享
01-09
03
AI 导读
01-07
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Jason Huang | 闽ICP备2025088096号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式