Java还要再学一遍基础(五)String,StringBuilder,StringBuffer

本文深入探讨了Java中String、StringBuilder及StringBuffer的区别与联系。详细介绍了String的常量池机制,StringBuilder与StringBuffer的内部实现原理,以及它们在不同场景下的应用。特别强调了StringBuilder在非并发场景下的性能优势。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

String,StringBuilder,StringBuffer学习

String,StringBuilder,StringBuffer的话题也是老生长谈了。权当记录一下。

1. String相关

  • 常量池:在编译期被确定,保存在.class文件中的一些常量,其中就有字符串。
  • String不属于Java的基本数据类型。是对象。
  • String被创建的时候会先去检查字符常量池里面有没有这个字符串,有的话直接使用,没有的话在字符常量池里面创建一个,再返回地址。
        String s1 = "what";
        String s2 = "what";
        System.out.println(s1 == s2);

上面的代码输出:

true

s1会被创建,s2直接使用s1中的地址。

  • 使用new String()的时候会先在对内存中申请一块区域存储对象,再去检查字符常量池是否有这个字符串。
        String s1 = "what";
        String s2 = new String("what");;
        System.out.println(s1 == s2);

输出:

false
  • 编译期不能确定的情况
        String s1 = "what0";
        String s2 = new String("what0");;
        int q = 0;
        String s3 = "what" + q;
        System.out.println(s1 == s2);
        System.out.println(s1 == s3);

输出:

false
false

因为q在编译期是无法被确定的所以返回false;

  • String的intern方法
    public native String intern();

一个本地方法,返回这个String对象在常量池中的引用。

        String s1 = "what0";
        String s2 = new String("what0");;
        int q = 0;
        String s3 = "what" + q;
        System.out.println(s1 == s2.intern());
        System.out.println(s1 == s3.intern());

输出:

true
true

比较的是常量池中的同一个引用,所以都是返回的true

因位字符串一旦改变就会重新创建,所以效率很低。

2. StringBuilder相关

  • 类定义
public final class StringBuilder
    extends AbstractStringBuilder
    implements java.io.Serializable, CharSequence

和StringBuffer都继承自AbstractStringBuilder类(String的变换相关的操作都被封装在里面,append,insert等)。同时实现序列化接口和字符序列接口。

  • 重要的属性
    /**
     * The value is used for character storage.
     */
    char[] value;

    /**
     * The count is the number of characters used.
     */
    int count;

实际上StringBuilder和StringBuffer都是用char[] 字符数组实现的。

  • 关键的构造器
    public StringBuilder() {
        super(16);
    }

    public StringBuilder(int capacity) {
        super(capacity);
    }

    public StringBuilder(String str) {
        super(str.length() + 16);
        append(str);
    }

父类对应的构造器:

AbstractStringBuilder(int capacity) {
        value = new char[capacity];
    }

默认的容量是16,也就是能容纳16个字符。同时也可以指定容量。

  • append方法
    public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();
        int len = str.length();
        ensureCapacityInternal(count + len);
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }

调用的是父类的方法,同时其中很重要的就是当容量不够的时候的处理:

    private void ensureCapacityInternal(int minimumCapacity) {
        // overflow-conscious code
        if (minimumCapacity - value.length > 0) {
            value = Arrays.copyOf(value,
                    newCapacity(minimumCapacity));
        }
    }

    private int newCapacity(int minCapacity) {
        // overflow-conscious code
        int newCapacity = (value.length << 1) + 2;
        if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }
        return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
            ? hugeCapacity(minCapacity)
            : newCapacity;
    }

这里着重关注的当然是newCapacity()方法

        int newCapacity = (value.length << 1) + 2;

默认的增长的容量为原容量的2倍加上2

        StringBuilder builder = new StringBuilder();
        System.out.println(builder.capacity());
        builder.append("01234567890123456");
        System.out.println(builder.capacity());

输出:

16
34

再看一下下面这一段代码:

        StringBuilder builder = new StringBuilder();
        System.out.println(builder.capacity());
        builder.append("012345678901234");
        System.out.println(builder.capacity());
        builder.append("01234567890123456789");
        System.out.println(builder.capacity());

输出:

16
16
35

这里第二次append的时候并不是直接扩容2倍再+2,而是刚好35。

if (newCapacity - minCapacity < 0) {
            newCapacity = minCapacity;
        }

原来:newCapacity - minCapacity也就是34 - 35是小于零的所以直接把35作为了新的容量。

所以并不是一定单纯的原来的容量*2 + 2,如果原来的容量*2 + 2还是不够的话就直接使用目标容量。

3. StringBuffer相关

  • StringBuffer的实现原理和StringBuilder是基本一样的。只是里面使用了多个synchronized来实现同步而已。但是相对效率上就会低一些。所以当涉及到并发的时候可以使用StringBuffer,单线程情况下StringBuilder效果更佳
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值