String、StringBuilder、StringBuffer之间的区别和转换

       今天遇到一个问题,因为String是不可变,当字符串要常改变,这用使用"+"的话会产生很多的内存对象,很不友好,所以有了对String类三兄弟:String、StringBuffer、StringBuilder的详解介绍并加深理解。

String类三兄弟简介

String StringBuffer StringBuilder
String是一个不可变类,所以它的值不可变的,这就导致一个问题,当字符串需要改变的时候,每次都会产生新的String对象,这样的操作不仅效率低,而且产生了大量的内存浪费 StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区域,当字符串大小没有超过容量时,不会分配新的容量时,当字符串大小超越容量,会自动增加容量 可变类、和StringBuffer的区别在于,StringBuffer的线程安全、StringBuilder线程不安全,下面介绍两者的区别
不可变类 可变类 可变类
线程安全 线程不安全
多线程操作字符串 单线程操作字符串

String类–String字符串常量

       String类和StringBuffer类的主要性能区别其实在于String是不可变的对象,因此在每次对String类对象进行改变时,其实都是产生了一个新的String对象,并将指针指向新的String对象,这样造成了String类的效率十分低,而且造成很多无用的内存对象,浪费内存,所以经常需要修改字符串内容的字符串最好不要使用String类。每次产生新的对象都会对系统产生新年影响,特别当内存中无引用对象多了,JVM的GC就会工作,那速度一定会受到一定程度的影响。

String操作时内存变换的图:
String、StringBuilder、StringBuffer之间的区别和转换
       可以看到,初始化String值为“hello”,然后在这个字符串后面加上新的字符串"world",这个过程需要在栈堆内存中开辟内存空间,最终得到了“hello world”字符串也相应的需要开辟内存空间,这样短短的两个字符串,却需要开辟三次内存,不得不说这是对内存空间的极大浪费。为了应对经常性的字符串相关的操作,这需要使用Java提供的其他两个操作字符串的类–StringBuffer和StringBuilder来对此变化进行处理。

       当对字符串进行修改时,特别是对字符串对象经常改变的情况下,最好使用StringBuffer和StringBulider,因为与String类不同的是,StringBuffer和StringBuilder可变类,当StringBuilder和StringBuffer对象被多次修改时,并不产生新的使用对象

三者的继承结构

String、StringBuilder、StringBuffer之间的区别和转换

三者的区别:

  • StringBuffer和StringBuilder非常类似,均代表可变的字符序列,而且方法也一样
  • String:不可变字符序列
  • StringBuffer:可变字符序列、效率低、线程安全
  • StringBuilder:可变字符序列、效率高、线程不安全

String使用陷阱:

String s="a";//创建了一个字符串 s=s+"b";//实际上原来的"a"字符串对象已经丢弃,现在又产生了一个字符串s+"b"(也就是"ab")。如果多次执行这些改变字符串内容的操作。如果这样的操作放在循环中,会极大影响程序的性能 

三者的转换

public class Solution {     public static void main(String[] args) {         String strA=new String("123");         System.out.println(strA);         //使用StringBuffer的构造函数StringBuffer(String s)来讲String对象变为StringBuffer类对象         StringBuffer strB=new StringBuffer(strA);         strB.append("456");         //使用StringBuffer的toString方法来完成两者的互转         System.out.println(strB.toString());          //StringBuilder类和StringBuffer相似,方法是一样的         StringBuilder strC=new StringBuilder(strA);         strC.append("123");         System.out.println(strC.toString());      } } 

StringBuffer和StringBuilder类的区别

       StringBuffer 字符串变量(线程安全),因为StringBuffer类的所有公共方法都被区别1:线程安全性
StringBuffer代码片段

@Override public synchronized StringBuffer append(String str) {     toStringCache = null;     super.append(str);     return this; } 

StringBuilder代码片段

    @Override     public StringBuilder append(String str) {         super.append(str);         return this;     } 

区别2:缓冲区
StringBuffer代码片段

private transient char[] toStringCache;  @Override public synchronized String toString() {     if (toStringCache == null) {         toStringCache = Arrays.copyOfRange(value, 0, count);     }     return new String(toStringCache, true); } 

StringBuilder代码片段

@Override public String toString() {     // Create a copy, don't share the array     return new String(value, 0, count); } 

可以看出,StringBuffer每次获取toString都会直接使用缓存区的toStringCache值来构造一个字符串。而StringBuilder则每次都需要复制一次字符串数组,在构造一个字符串。
StringBuilder则每次都需要复制一次字符数组,在构造一个字符串。

区别3:性能
       既然 StringBuffer 是线程安全的,它的所有公开方法都是同步的,StringBuilder 是没有对方法加锁同步的,所以毫无疑问,StringBuilder 的性能要远大于 StringBuffer。
       StringBuffer适用于在于多线程操作同一个StringBuffer的场景,如果是单线程场合StringBuilder更适合。

文章内容参考了以下博客:

https://blog.csdn.net/itchuxuezhe_yang/article/details/89966303 https://segmentfault.com/a/1190000017909550