(转)Java中的String、StringBuilder和StringBuffer

发布时间 2023-05-06 18:04:32作者: bruce_he

1、String

String对象是不可变的,即一旦一个 String 对象被创建以后,包含在这个对象中的字符序列是不可改变的,直至这个对象被销毁。

那么我们new一个String对象,比如

String a = new String("A")
String a2 = new String("A")

和直接创建一个字符串,比如

String b = "A"

这两种方法有什么区别呢。

对于第一种方法,当new一个String对象时会在栈空间开辟一块空间存放引用a,在堆空间中开辟一块空间存放一个新建的"A"对象,栈空间的引用指向堆空间中的新对象,如果存在两个相同的字符串,则会分配不同的内存地址,调用intern方法,intern方法会从字符串常量池中查询当前字符串是否存在,如果存在,就直接返回当前字符串,如果不存在就会将当前字符串放入常量池中,之后再返回;对于第二种方法,直接创建的时候,会先查看字符串常量池有没有相同的字符串,如果没有"A"会存放在字符串常量池,如果有引用则直接指向常量池中的地址。

说到这里关于字符串常量池,究竟是在方法区中,还是在堆中可以看一下这篇文章

字符串常量池和运行时常量池是在堆还是在方法区?

2、StringBuilder

Sting对象是不可变的,那么关于字符串的拼接是怎么实现的呢。

public static void main(String[] args) {
    String b = "cd";
    String s = "ab" + b + "ef";
    System.out.println(s); //abcdef
}

编译器会创建一个StringBuilder对象,用以构造最终的String,并为每个字符串调用一次StringBuilder的append()方法,总计三次。最终调用toString()生成结果。

StringBuilder在进行append连接字符串的时候并不是用String存储,而是存放到一个名为value的char数组当中,Sring中的value由final修饰,而另外两种可变字符串对象的value数组是可以扩容的,这样就不需要不停创建对象了。

数组默认的初始长度是16,扩容系数是value.length * 2 + 2,也即 (value.length << 1) + 2,而且只有当append之后的数据长度大于value.length时才会扩容一次,并不是每次连接都会进行扩容操作。

 

3、StringBuffer

StringBuilder 和 StringBuffer 功能基本相似,方法也差不多。不同的是,StringBuffer的所有公开方法都是synchronized修饰的,而StringBuilder并没有synchronized修饰。StringBuffer 是线程安全的,而 StringBuilder 则没有实现线程安全功能,所以性能略高。因此在通常情况下,如果需要创建一个内容可变的字符串对象,则应该优先考虑使用 StringBuilder 类。

————————————————
原文链接:https://blog.csdn.net/weixin_44153131/article/details/126187193