String、StringBuffer、StringBuilder

String、StringBuffer、StringBuilder

String

final class

    • 所有属性也都是 final 的
    • 原生的保证了基础线程安全
      • 因为无法对它内部数据进行任何修改

典型的 Immutable 类

    • 所以拼接、裁剪字符串等动作,都会产生新的 String 对象
      • 对应用性能有明显影响
      • 操作不当可能会产生大量临时字符串

StringBuffer

可修改字符序列

    • StringBuffer 和 StringBuilder 底层都是利用可修改的(char,JDK 9 以后是 byte)数组
    • 继承了 AbstractStringBuilder

把各种修改数据的方法都加上 synchronized 关键字

    • 线程安全
      • 也随之带来了额外的性能开销
    • 简单粗暴

StringBuilder

可修改字符序列

    • 在能力上和 StringBuffer 基本相同
    • 继承了 AbstractStringBuilder

Java 1.5 中新增

    • 是绝大部分情况下进行字符串拼接的首选

线程不安全

    • 有效减小了开销

内部数组

内部数组的大小应该如何决定呢?

目前的实现

    • 构建时初始字符串长度加 16
      • 如果构建对象时没有输入最初的字符串
        • 初始值就是 16
      • 可以在创建时,主动指定合适的大小
    • 扩容会产生多重开销
      • 要抛弃原有数组,创建新的数组,还要进行 arraycopy

String的演化

在历史版本中,使用 char 数组保存数据

    • 非常直接
    • Java 中的 char 是两个 bytes 大小
      • 但拉丁语系语言的字符不需要太宽的 char
      • 这样无区别的实现就产生了一定的浪费

Compact Strings

    • 将数据存储方式从 char 数组改变为一个 byte 数组加上一个标识编码的所谓 coder,并且将相关字符串操作类都进行了修改
    • 紧凑字符串
      • 更小的内存占用、更快的操作速度
    • 所有相关的 Intrinsic 之类也都进行了重写
      • 保证没有任何性能损失。
    • 这个特性对于绝大部分应用来说是透明的
      • 因为虽然底层实现发生了改变,但 Java 字符串的行为并没有大的变化,
      • 绝大部分情况不需要修改已有代码

字符串缓存

intern 机制

Intern 是一种显式地排重机制

    • Java的intern机制是指在运行时,如果一个字符串常量(即用双引号括起来的字符串字面量)已经存在于字符串池中,那么在创建新的该字符串常量时,会返回已存在的字符串常量的引用,而不是新创建一个对象。

intern() 方法

    • 作用是提示 JVM 把相应字符串缓存起来,以备重复使用。
    • String 在 Java 6 以后提供
    • 创建字符串对象并调用 intern() 方法时
      • 如果字符串常量池中已经有缓存的字符串
        • 返回缓存里的实例
      • 如果没有
        • 将此String对象添加到池中缓存起来

早期的版本保存在 PermGen中

    • PermGen也就是"永久代"
    • 这个空间是很有限的
    • 基本不会被 FullGC 之外的垃圾收集照顾到
    • 所以,如果使用不当,OOM 就会光顾。

后续版本中保存在堆中

    • 避免永久代占满的问题
      • 永久代在 JDK 8 中被 MetaSpace(元数据区)替代
    • 默认缓存大小也在不断地扩大中
      • -XX:+PrintStringTableStatistics
        • 查看默认缓存
      • -XX:StringTableSize=N
        • 调整默认缓存

G1 GC 下的字符串排重

在 Oracle JDK 8u20 之后,推出了这个新的特性

将相同数据的字符串指向同一份数据

    • JVM 底层的改变,因此不需要修改 Java 类库

目前是默认关闭的

    • -XX:+UseStringDeduplication
      • 开启G1 GC 下的字符串排重功能

Intrinsic 机制

JVM 的底层优化机制

运行的往往就是特殊优化的本地代码,而不是 Java 代码生成的字节码

一种利用 native 方式 hard-coded 的逻辑

-XX:+PrintCompilation -XX:+UnlockDiagnosticVMOptions -XX:+PrintInlining

    • 查看 intrinsic 发生的状态
相关推荐
y1su2 分钟前
Leetcode 字符串模板
java·数据结构·算法·leetcode·职场和发展·动态规划
我命由我123451 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
苜蓿muxu2 小时前
Java 字符串拼接:+、StringBuilder、StringBuffer的区别
java
摇滚侠2 小时前
《Java并发编程之美》第 4 章 Java 并发包中原子操作类原理剖析 阅读笔记 7
java·笔记·python
旋律4142 小时前
同义方法区别(增加类与删除类)
java·后端
学到老活到老3 小时前
方法执行完了,对象为什么还占着内存?
java·jvm
用户7771298509123 小时前
常见的同义方法的区别:增加类和删除类
java·后端
十年Java程序媛3 小时前
Java this 与 super 详解|继承高频踩坑 + 面试题整理
java·spring boot·面试
用户7771298509123 小时前
Stream流式使用
java