为什么String在Java中是不可变的?以及Java中的StringBuilder和StringBuffer

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"会存放在字符串常量池,如果有引用则直接指向常量池中的地址。

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

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

那么为什么String被设计为不可变?

1.1 字符串常量池的要求

字符串常量池是方法区中的特殊存储区域。创建字符串时,如果池中已存在该字符串,则将返回现有字符串的引用,而不是创建新对象。

下面的代码将在堆中仅创建一个字符串对象

String string1 = "abcd";
String string2 = "abcd";

在这里插入图片描述
如果字符串是可变的,则使用一个引用更改字符串将导致其他引用的值错误。

1.2 缓存Hashcode

字符串的Hashcode在 Java 中经常使用。例如,在 HashMap 或 HashSet 中。不可变保证Hashcode将始终相同,无需担心更改。这意味着无需每次使用时都计算Hashcode,效率更高。

1.3 安全性

字符串被广泛用作许多Java类的参数,例如网络连接,打开文件等。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。

1.4 不可变对象本质上是线程安全的

由于不可变对象无法更改,因此可以在多个线程之间自由共享它们。


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 类。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值