String的不可变性

本文探讨了Java中String类型的不可变性,分析了为何String对象的属性不能被修改,并解释了这种特性在函数参数传递、字符串常量池、哈希码计算以及线程安全性等方面的优势。此外,不可变性对于优化性能和确保并发环境下的数据一致性至关重要。
摘要由CSDN通过智能技术生成

java中的字符串

字符串,顾名思义就是一串字符,也就是一串连续的char.在c语言中就是用的char数组来表示的字符串.在java的一切皆对象世界中,将char数组进行了封装,用string类型来表达字符串.

java中string的源码

//java8源码
public final class String{
	private final char value[];
}

我们可以看到char数组被final关键字所修饰,并且是私有成员变量.
那么为什么java中要这么设计呢?这就要提到String的不可变性了.

String的不可变性

//Person是可变的
Person p = new Person(18);
p.setAge(20);

//String 是不可变的
String s = "JAVA";

如果我们可以修改对象的属性,那么我们就可以说,这个对象时可变的,反之,则是不可变的.
那么,String怎么就是不可变的了?

String s = "Java";
s="JavaScript";

System.out.println(s);//JavaScript

转自B站RudeCrab
我们要注意,对象的不可变性,是指对象本身的属性或者说本身的数据不会改变,将变量重新赋值,我们是创建了一个新对象,让后将新对象的引用赋值给了变量(这里我们又要提到java只支持值传递,而对对象的传递,我们传递的是地址值),之前的对象是没有受到影响的.
Java中string的不可变性,不仅是源码之中char数组被private final所修饰,而且并没有提供任何修改字符数组的方法.一些字符串操作都是返回的新String对象,不会影响到原始数据.获取其底层字符数组时,都是复制一个新数组进行返回,原数组也不会受到影响.并且String类型还被final修饰了,代表其不可被继承,从而杜绝了子类覆盖父类行为的可能性.

String作为函数参数传递

String是特殊的引用类型,一旦初始化则是不可变的,可以当做是基本数据类型看待,因为基本数据类型也是不可变的。
String与基本数据类型作为参数传递时,传递的只是值的一个副本,在函数中对数据进行操作,不会改变原有的值,改变的只是副本值。
但是我们又知道java机制是只支持值传递,那么传递一般的对象,那不应该传递的是引用吗?
其实,java认为,即使传递的是引用,也把他看成地址值传递,所以就是值传递,实际上可以说是引用传递了,只不过传递的是地址值。
将对象作为参数传递,函数中对对象进行操作时,实际改变的就是对象本身,不存在副本或拷贝的情况。

为什么java中要设计String的不可变性

首先,只有String不可变了,堆中的字符串常量池才能发挥作用,用字面量创建字符串时,字符串常量池会返回已有对象的引用,如果字符串可变,那引用的值就可以随时改变,并能随时影响到其他的引用,从而数据会发生各种错误,这样常量池还谈何复用呢?
然后String不可变可以保证他的hash码也不会变,因此计算一次hash码后,就可以将其缓存,再用到时就无需计算了,性能更高.
也正是由于哈希码不会变,所以能搞放心的去使用与哈希码相关的对象,比如HashMap HashSet ,如果String的哈希码会变,那就会影响到这些对象的哈希计算,从而导致预期之外的结果,不如你之前明明存储了一个String的对象,到最后你找不到原对象了,

在这里插入图片描述
最后一个很重要的原因是,不可变对象都是线程安全的,因此你不用担心当前线程使用的对象会被其他的线程所改变,可以发现不可变对象有诸多的优点,所以java中有许多对象都设计成了不可变的,比如BigDecimal.

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值