Java StringBuffer和StringBuilder和String韩顺平跟学

StringBuffer

StringBuffer

知识点解读(StringBuffer源码分析)

StringBuffer源码分析
父类

  1. StringBuffer 的直接父类是 AbstractStringBuilder
  2. StringBuffer 实现了 Serializable 即StringBuffer的对象可以串行
  3. 在父类中有一个属性 char[] value,不是final常量,该value存放字符串内容(存放在堆中的)
  4. StringBuffer是一个final类,不能被继承
  5. 因为StringBuffer 字符内容是存在 char[] value,所以在变化的时候(例如:新增/删除),不用每次都更换地址,即:创建新对象(即:不是每次都创建新对象),所以效率高于String

String 和 StringBuffer

  1. String保存的是字符串常量,里面的值不能更改,每次String类的更新实际上就是改地址,效率最低
  2. StringBuffer保存的是字符串变量,里面的值可以修改,每次StringBuffer的更新实际上可以更新内容,不用每次更新地址,效率更高。

// char[] value放在堆

String 和 StringBuffer相互转换

String 和  StringBuffer相互转换

public static void main(String[] args) {
	// TODO Auto-generated method stub
	//	构造器的使用
	// 1.创建1个大小为16的char[]数组,用于存放16字符的数据内容
	StringBuffer stringBuffer = new StringBuffer();
	// 2.通过构造器指定 char[] 的大小
	StringBuffer stringBuffer2 = new StringBuffer(100);
	// 3.通过给一个String 创建 StringBuffer:当前字符串长度(str.length) + 16
	StringBuffer stringBuffer3 = new StringBuffer("Hello");
	// 4.String 和 StringBuffer 的转换
	// 方式1:  使用构造器
	// 注意:返回的才是StringBuffer对象,对str本身没有影响
	String str = "Hello world";
	StringBuffer stringBuffer4 = new StringBuffer(str);
	System.out.println("str: " + str);
	System.out.println("stringBuffer4: " + stringBuffer4);
	
	// 方式2 :使用append方法
	StringBuffer stringBuffer5 = new StringBuffer();
	stringBuffer5.append(str);
	System.out.println("stringBuffer5: " + stringBuffer5);
	
	// StringBuffer → String
	// 1.用toString()方法转化
	StringBuffer stringBuffer6 = new StringBuffer("你好");
	System.out.println("stringBuffer6.toString(): " + stringBuffer6.toString());
	
	// 2.使用构造器
	StringBuffer stringBuffer7 = new StringBuffer("转换");
	String s = new String(stringBuffer7);
	System.out.println("s:" +s);
	
	// 常用方法
	StringBuffer stringBuffer8 = new StringBuffer("hello");
	// 增加 append
	stringBuffer8.append(",");
	stringBuffer8.append("张三丰");
	stringBuffer8.append("18").append(true).append(100);
	System.out.println("stringBuffer8 append:" + stringBuffer8); // 输出:hello,张三丰18true100
	// 删除 delete(start,end) 删除start——end的字符,但是不包含end位置的字符
	stringBuffer8.delete(0, 3);
	System.out.println("stringBuffer8 delete:" + stringBuffer8); // 输出:lo,张三丰18true100
	// 更改 replace(start,end,String)
	stringBuffer8.replace(0, 2,"01");
	System.out.println("stringBuffer8 replace:" + stringBuffer8); // 输出:01,张三丰18true100
	
	// 查询 indexOf 查找指定字符串第一次出现的索引,找不到返回-1
	System.out.println("stringBuffer8 indexOf:" + stringBuffer8.indexOf("张三丰")); // 输出:3

	// 插入 insert 指定一个位置插入字符串,原先位置自动后移
	stringBuffer8.insert(3, "我是");
	System.out.println("stringBuffer8 insert:" + stringBuffer8); // 输出:01,我是张三丰18true100

	// 获取长度 length
	System.out.println("stringBuffer8 length:" + stringBuffer8.length()); // 输出:17

};

length()与capacity()

package com.StringBuffer;

import org.junit.Test;

/**
 * @author wty
 * @date 2022/11/17 16:37
 */
public class StringBufferEx05 {
    @Test
    public void test(){
        StringBuffer stringBuffer = new StringBuffer(10);
        stringBuffer.append("12345");
        System.out.println(stringBuffer.length());
        System.out.println(stringBuffer.capacity());
        /**
         * 输出结果
         * 5
         * 10
         */

        stringBuffer.append("123456");
        System.out.println(stringBuffer.length());
        System.out.println(stringBuffer.capacity());
        /**
         * 输出结果
         * 5
         * 10
         * 11
         * 22  扩容了一倍
         *
         * 扩容源码
         *     public AbstractStringBuilder append(String var1) {
         *         if (var1 == null) {
         *             return this.appendNull();
         *         } else {
         *              // var1 = 11这里进行扩容
         *             int var2 = var1.length();
         *             // 这里进行扩容
         *             this.ensureCapacityInternal(this.count + var2);
         *             var1.getChars(0, var2, this.value, this.count);
         *             this.count += var2;
         *             return this;
         *         }
         *     }
         */
    }
}

练习题:

 @Test
    public void testStringBuffer(){
        StringBuffer stringBuffer2 = new StringBuffer();
        String c = null;
        stringBuffer2.append(c);
        System.out.println(stringBuffer2.length()); // 这里会输出什么
        System.out.println(stringBuffer2);

        /**源码解读:
         * // public AbstractStringBuilder append(String var1) {
         * if (var1 == null) {
         *return this.appendNull();
         *}
         *
         *  private AbstractStringBuilder appendNull() {
         *  int var1 = this.count; // 0
         *  this.ensureCapacityInternal(var1 + 4); // 4
         *  char[] var2 = this.value; // ,,,,,,,,
         *  var2[var1++] = 'n'; //var2[0] = n
         *  var2[var1++] = 'u'; //var2[1] = u
         *  var2[var1++] = 'l'; //var2[2] = l
         *  var2[var1++] = 'l'; //var2[3] = l
         *  this.count = var1; // var1 = 4
         * return this; // 返回4
         }
         *
         */
        StringBuffer stringBuffer3 = new StringBuffer(c); // java.lang.NullPointerException
        /**
         * 源码解读:
         *
         *     public StringBuffer(String var1) {
         *         super(var1.length() + 16); // 这里抛出空指针异常
         *         this.append(var1);
         *     }
         *
         */
        System.out.println(stringBuffer3);
    }

课后练习:小数点前,每3位1个逗号

课后练习:小数点前,每3位1个逗号

package com.StringBuffer;

import org.junit.Test;

import java.util.Scanner;

/**
 * @author wty
 * @date 2022/10/14 0:16
 */
public class HomeWork03 {
    @Test
    public void getStringBuffer() {
        System.out.println("请输入商品名称");
        Scanner scanner = new Scanner(System.in);
        String a = scanner.nextLine();

        System.out.println("请输入商品价格");
        Scanner scanner2 = new Scanner(System.in);
        String b = scanner2.nextLine();

        // 先找到小数点
        StringBuffer stringBuffer = new StringBuffer(b);
        if (stringBuffer.indexOf(".") > 0) {

            for (int i = stringBuffer.lastIndexOf(".") - 3; i > 0; i -= 3) {
                if (i < 0) {
                    break;
                }
                stringBuffer.insert(i, ",");
            }
        } else {
            for (int i = stringBuffer.length() - 3; i > 0; i -= 3) {
                if (i < 0) {
                    break;
                }
                stringBuffer.insert(i, ",");
            }
        }
        System.out.println(a + "    " + stringBuffer);

    }
}

StringBuilder


基本介绍

  1. 一个可变的字符序列,此类提供了一个与StringBuffer兼容的API,但不能保证同步(StringBuilder 不是线程安全的),该类被设计用作StringBuffer的一个简易替换,**用在字符串缓冲区被单个线程使用的时候。**如果可以,单线程建议优先使用StringBuilder,它比StringBuffer快。
  2. 在StringBuilder上的主要操作是append和insert方法,可以重载这些方法,可以接受任意类型的数据。

StringBuilder源码阅读

StringBuilder源码阅读

public static void main(String[] args) {
	// TODO Auto-generated method stub
	// 1.StringBuilder继承了 AbstractStringBuilder类型
	// 2.实现了Serializable(可串行的),说明StringBuilder对象是可以串行化的(对象可以网络传输,可以保存到文件)
	// 3.StringBuilder 是final类,不能被继承
	// 4.StringBuilder对象的字符序列,仍然存放在其父类AbstractStringBuilder的 char[] value
	// 因此,因此字符序列存放在堆中
	// 5.stringBuilder的所有方法没有做互斥的处理,即没有synchronized(同步)关键字处理,因此在单线程的情况下使用stringBuilder
	StringBuilder stringBuilder = new StringBuilder();
}

为什么说StringBuffer是线程安全而StringBuilder不是

StringBuffer

可以看到相关操作被synchronized修饰
StringBuffer线程安全

StringBuilder

没有被synchronized修饰
StringBuilder不安全


String、StringBuffer和StringBuilder的比较

  1. StringBuffer和StringBuilder非常类似,均代表可变的字符序列,而且方法也一样。
  2. String:不可变的字符序列,效率低,但是复用率高
  3. StringBuffer:可变字符序列、效率较高(增删)、线程安全。
  4. StringBuilder:可变字符序列、效率最高,线程不安全
  5. String的注意事项 如果对字符串做大量修改,并且放在循环中,多线程用StringBuffer,单线程用StringBuilder,而不要使用String

注意事项

名称是否可变效率线程安全
String不可变的字符序列效率低3
StringBuffer可变的字符序列效率较高2线程安全
StringBuilder可变的字符序列效率最高1线程不安全

效率

StringBuilder > StringBuffer > String

package com.StringBuffer;

import org.junit.Test;

/**
 * @author wty
 * @date 2022/11/17 16:48
 */
public class StringBuilderEx {
    @Test
    public void test(){
        long startTime = 0L;
        long endTime = 0L;
        StringBuffer buffer = new StringBuffer("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 80000; i++) {//StringBuffer 拼接 20000 次
            buffer.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer 的执行时间:" + (endTime - startTime));
        StringBuilder builder = new StringBuilder("");
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 80000; i++) {//StringBuilder 拼接 20000 次
            builder.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder 的执行时间:" + (endTime - startTime));
        String text = "";
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 80000; i++) {//String 拼接 20000
            text = text + i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("String 的执行时间:" + (endTime - startTime));
    }
}

执行结果

StringBuffer 的执行时间:19
StringBuilder 的执行时间:8
String 的执行时间:5766

使用原则

  1. 如果字符串存在大量的修改操作,一般用StringBuilder或StringBuffer
  2. 如果字符串存在大量的修改操作,并在单线程的情况下,那么使用 StringBuilder
  3. 如果字符串存在大量的修改操作,并在多线程的情况下,那么使用 StringBuffer
  4. 如果我们字符串很少修改,被多个对象引用,使用String,比如配置信息等
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

心向阳光的天域

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

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

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

打赏作者

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

抵扣说明:

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

余额充值