String、StringBuffer、StringBuilder区别

最近我有了新的理解

  • String
public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

String 类中使用 final 关键字修饰字符数组来保存字符串,因此String对象不可变,这句话不正确
我们知道被 final 关键字修饰的类不能被继承,修饰的方法不能被重写,修饰的变量是基本数据类型则值不能改变,修饰的变量是引用类型则不能再指向其他对象。因此,final 关键字修饰的数组保存字符串并不是 String 不可变的根本原因,因为这个数组保存的字符串是可变的。如果引用为引用数据类型,比如对象、数组,则该对象、数组本身可以修改,但指向该对象或数组的地址的引用不能修改。
String 真正不可变有下面几点原因:

  • 保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法.
  • String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变.
  • StringBuilder/StringBuffer
abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;


两者继承父类AbstractStringBuilder ,底层也是字符数组,当时没有private和final修饰,而且提供很多修改字符数组的方法

  • 线程安全性:String不可变,常量,安全,StringBuilder/StringBuffer都继承AbstractStringBuilder ,存在很多公共方法.但是StringBuffer 有同步锁,线程安全.反之,StringBuilder没有同步锁,不安全.
  • 性能:每次改变String的时候,都会新建String对象,浪费内存,降低性能.StringBuffer 有锁机制,原地改变,还是会浪费性能.StringBuilder不存在锁机制,原地改变,不考虑安全前提,性能好.
    总结:大数据,多线程,安全->StringBuffer ;大数据,单线程->StringBuilder;小数据,安全->String
String str1 = "he";
        String str2 = "llo";
        String str3 = "world";
        String str4 = str1 + str2 + str3;
// class version 52.0 (52)
// access flags 0x21
public class practice/begin/Code25_Demo {

  // compiled from: Code25_Demo.java

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 8 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lpractice/begin/Code25_Demo; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x9
  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 10 L0
    LDC "he"
    ASTORE 1
   L1
    LINENUMBER 11 L1
    LDC "llo"
    ASTORE 2
   L2
    LINENUMBER 12 L2
    LDC "world"
    ASTORE 3
   L3
    LINENUMBER 13 L3
    NEW java/lang/StringBuilder
    DUP
    INVOKESPECIAL java/lang/StringBuilder.<init> ()V
    ALOAD 1
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    ALOAD 3
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    ASTORE 4
   L4
    LINENUMBER 15 L4
    RETURN
   L5
    LOCALVARIABLE args [Ljava/lang/String; L0 L5 0
    LOCALVARIABLE str1 Ljava/lang/String; L1 L5 1
    LOCALVARIABLE str2 Ljava/lang/String; L2 L5 2
    LOCALVARIABLE str3 Ljava/lang/String; L3 L5 3
    LOCALVARIABLE str4 Ljava/lang/String; L4 L5 4
    MAXSTACK = 2
    MAXLOCALS = 5
}

对象引用和“+”的字符串拼接方式,实际上是通过 StringBuilder 调用 append() 方法实现的,拼接完成之后调用 toString() 得到一个 String 对象 。

String[] arr = {"he", "llo", "world"};
        String s = "";
        for (int i = 0; i < arr.length; i++) {
            s += arr[i];
        }
        System.out.println(s);
// class version 52.0 (52)
// access flags 0x21
public class practice/begin/Code25_Demo {

  // compiled from: Code25_Demo.java

  // access flags 0x1
  public <init>()V
   L0
    LINENUMBER 8 L0
    ALOAD 0
    INVOKESPECIAL java/lang/Object.<init> ()V
    RETURN
   L1
    LOCALVARIABLE this Lpractice/begin/Code25_Demo; L0 L1 0
    MAXSTACK = 1
    MAXLOCALS = 1

  // access flags 0x9
  public static main([Ljava/lang/String;)V
   L0
    LINENUMBER 14 L0
    ICONST_3
    ANEWARRAY java/lang/String
    DUP
    ICONST_0
    LDC "he"
    AASTORE
    DUP
    ICONST_1
    LDC "llo"
    AASTORE
    DUP
    ICONST_2
    LDC "world"
    AASTORE
    ASTORE 1
   L1
    LINENUMBER 15 L1
    LDC ""
    ASTORE 2
   L2
    LINENUMBER 16 L2
    ICONST_0
    ISTORE 3
   L3
   FRAME APPEND [[Ljava/lang/String; java/lang/String I]
    ILOAD 3
    ALOAD 1
    ARRAYLENGTH
    IF_ICMPGE L4
   L5
    LINENUMBER 17 L5
    NEW java/lang/StringBuilder
    DUP
    INVOKESPECIAL java/lang/StringBuilder.<init> ()V
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    ALOAD 1
    ILOAD 3
    AALOAD
    INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
    ASTORE 2
   L6
    LINENUMBER 16 L6
    IINC 3 1
    GOTO L3
   L4
    LINENUMBER 19 L4
   FRAME CHOP 1
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 2
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L7
    LINENUMBER 22 L7
    RETURN
   L8
    LOCALVARIABLE i I L3 L4 3
    LOCALVARIABLE args [Ljava/lang/String; L0 L8 0
    LOCALVARIABLE arr [Ljava/lang/String; L1 L8 1
    LOCALVARIABLE s Ljava/lang/String; L2 L8 2
    MAXSTACK = 4
    MAXLOCALS = 4
}

编译器不会创建单个 StringBuilder 以复用,会导致创建过多的 StringBuilder 对象。浪费空间.因此,在循环中进行字符串拼接,直接使用StringBuilder比较好.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zs浪里小白龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值