java--(StringBuilder)

上一节我们讲解了String,这一节我们来讲解StringBuilder。同样让我们带着疑问来学习:

1.什么是StringBuilder?

2.为什么要有StringBuilder?

一、什么是StringBuilder?

        StringBuilder可以看成是一个容器,创建之后里面的内容是可变的

二、为什么要有StringBuilder

       回答这个问题之前,让我们先看一个例子:

public class demo99 {
    public static void main(String[] args) {
        String s1="a";
        String s2=s1+"b";
        String s3=s2+"c";
        System.out.println(s3);
    }
}

假若我要做以上代码所表达的操作,就是对字符串进行拼接,从上一节我们知道,字符串本身是不可变的,所以每一次拼接都要创建一个新的对象并返回,这里只是拼接三个,如果我要拼接上万个呢?这就需要拼接一次创建一次对象,这样就很非常影响我们的内存和程序的效率。这并不是我们想要的,我们想要的肯定是一个快捷的方式,于是就引入了StringBuilder:

作用:提高字符串的操作效率。

那么它是怎么提高字符串的操作效率的呢?直接看内存原理图和代码比较好理解为什么提高了拼接效率:

public class demo99 {
    public static void main(String[] args) {
        StringBuilder sb=new StringBuilder("");
        sb.append("a");
        sb.append("b");
        sb.append("c");
        System.out.println(sb);
    }
}

我们这里的操作也是abc进行拼接,我们还是用javap -v demo99.class查看字节码文件

Constant pool:
   #1 = Methodref          #10.#19        // java/lang/Object."<init>":()V
   #2 = Class              #20            // java/lang/StringBuilder
   #3 = String             #21            // hello
   #4 = Methodref          #2.#22         // java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   #5 = String             #23            // a
   #6 = Methodref          #2.#24         // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   #7 = String             #25            // b
   #8 = String             #26            // c

   #9 = Class              #27            // stringDemo/demo99
  #10 = Class              #28            // java/lang/Object
  #11 = Utf8               <init>
  #12 = Utf8               ()V
  #13 = Utf8               Code
  #14 = Utf8               LineNumberTable
  #15 = Utf8               main
  #16 = Utf8               ([Ljava/lang/String;)V
  #17 = Utf8               SourceFile
  #18 = Utf8               demo99.java
  #19 = NameAndType        #11:#12        // "<init>":()V
  #20 = Utf8               java/lang/StringBuilder
  #21 = Utf8               hello
  #22 = NameAndType        #11:#29        // "<init>":(Ljava/lang/String;)V
  #23 = Utf8               a
  #24 = NameAndType        #30:#31        // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  #25 = Utf8               b
  #26 = Utf8               c
  #27 = Utf8               stringDemo/demo99
  #28 = Utf8               java/lang/Object
  #29 = Utf8               (Ljava/lang/String;)V
  #30 = Utf8               append
  #31 = Utf8               (Ljava/lang/String;)Ljava/lang/StringBuilder;
{
  public stringDemo.demo99();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 3: 0

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=2, args_size=1
         0: new           #2                  // class java/lang/StringBuilder
         3: dup
         4: ldc           #3                  // String hello
         6: invokespecial #4                  // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
         9: astore_1
        10: aload_1
        11: ldc           #5                  // String a
        13: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        16: pop
        17: aload_1
        18: ldc           #7                  // String b
        20: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        23: pop
        24: aload_1
        25: ldc           #8                  // String c
        27: invokevirtual #6                  // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
        30: pop
        31: return

 通过字节码文件我们可以看到常量池中仅仅是创建一个三个对象a,b,c。然后在堆中创建了一个StringBuilder对象。让我们来看下这两种拼接方式内存的原理图:

1.+连接符的拼接方式:

我们从图中可以看到,每次拼接都需要创建一个StringBuilder对象,然后StringBuilder在调用toString方法返回字符串,这种方法每次拼接都要再堆中创建两个对象。

有可能有人会疑问,为什么toString的方法还创建对象了呢?我们来一看以下源码:

@Override
public String toString() {
    // Create a copy, don't share the array
    return new String(value, 0, count);//创建了一个新的字符串对象
}

2.StringBuilder的方法内存原理:

可以看到,所有拼接的内容都会往StringBuilder中放,不会创建很多无用的空间,节约内存,提高了效率。

学到这里可能会有人问,StringBuilder这样一直往里放内容,会不会爆呢?让我们来看一下原码分析:

  public StringBuilder() {
        super(16);
    }

可以看到再进行初始化的时候:

默认的容量大小是16

然后,如果要进行再添加的话分两种情况:

第一种:容量足够的话,直接进行添加就行

第二种:容量不够的情况下,扩充也会分为两种:

        1.添加的内容大于16会扩容,扩容后的容量是(原来的容量*2+2)

        2.如果扩容之后还不够,以实际长度为准

下面是这第两种情况的代码

private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;//扩充为原来的两倍+2
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;//扩充后不够以实际为准
        }
    }

 

该内容学习来自#黑马程序员java,并对其进行了扩充整理。

视频链接:字符串-10-StringBuilder的基本操作_哔哩哔哩_bilibili

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值