深入理解String,StringBuilder,StringBuffer

首先明确什么是不可变字符序列?
我们都知道在Java中, String类是不可变的。那么到底什么是不可变的对象呢? 可以这样理解:如果一个对象创建完成之后,不能再改变它的状态,那么该对象就是不可变的。不能改变状态的意思是,不能改变对象内的属性,包括基本数据类型的值不能改变,引用类型指向的对象的状态也不能改变。或者这样理解就是对象状态不可变,而引用是可再次指向其他对象的。
首先说明一点不是说String类被final修饰就是不可变的,而是成员变量(域)被final修饰
源码中是这样体现的
/** The value is used for character storage. */
private final char value[];
具体看如下代码运行结果(都是针对同一对象进行修改操作)

public class Demo01 {
	  public static void main(String[] args) {
			String s1=new String("abcdef");
			
			System.out.println(Integer.toHexString(s1.hashCode()));
			System.out.println(s1);
			
			s1.substring(3, 5);
			
			System.out.println(Integer.toHexString(s1.hashCode()));
			System.out.println(s1);
		}
}

内存地址为ab199863
abcdef
内存地址为ab199863
abcdef
对同一对象进行修改操作没有发生改变即为不可变
为什么StringBuilder与StringBuffer是可变的?
源码中是这样体现的(摘自父类AbstractStringBuilder)
/**
* The value is used for character storage.
*/
char[] value;

public class Demo02 {
>         public static void main(String[] args) {
>     		StringBuilder sb=new StringBuilder("abcdef");
>     		
>     		System.out.println(Integer.toHexString(sb.hashCode()));
>     		System.out.println(sb);
>     		
>     		sb.setCharAt(0, 'A');
>     		
>     		System.out.println(Integer.toHexString(sb.hashCode()));
>     		System.out.println(sb);
>     	}
>     }

内存地址为15db9742
abcdef
内存地址为15db9742
Abcdef
对同一对象进行修改操作发生改变即为可变

接下来看三者间的效率
我们对5万个数进行字符串拼接效率如下
在这里插入图片描述
如图可得,三者间的效率差距有多大
StringBuilder与StringBuffer的区别
StringBuilder:线程不安全,效率高
StringBuffer:线程安全:效率低

摘自JDK1.8 StringBuffer的append部分重载方法源码

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

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

由于append方法加了同步拼接时导致效率低
return this可以进行链式调用

根据effective java第51条规定:
通过字符串连接符进行操作时,时间复杂度为O(n2),这是由于字符串不可变而导致的结果,当两个字符串被连接在一起时,他们的内容都要被拷贝,相反,而应该使用StringBuilder的append方法,时间是线性的,另一种方法是使用字符数组,或者每次只处理一个字符串

可变即可扩容

void expandCapacity(int minimumCapacity) {
        int newCapacity = value.length * 2 + 2;
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        value = Arrays.copyOf(value, newCapacity);
    } 

扩容实际上就是数组的拷贝

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值