String为什么是不可变的?

我们谈论的String不可变, 指的是字符串的值不可变

1,什么是不可变对象?

如果一个对象,在它创建完成之后,不能再改变它的状态,那么这个对象就是不可变的。

不能改变状态的意思是:不能改变对象内的成员变量,包括基本数据类型的值不能改变,引用类型的变量不被指向其他的对象,引 用类型指向的对象的状态也不能改变。

2,以下情况为什么说String对象是不可变的呢?

public class Demo { String str = "ABC"; System.out.println("s = " + str); //"ABC" str = "123"; System.out.println("s = " + str);// "123"; }

str只是一个String对象的引用,并不是对象本身,对象在内存中是一块内存区,放在堆中,成员变量越多,这块内存区占的空间越大,引用只是一个4字节的数据,里面存放了它所指向的对象的地址,通过这个地址可以访问对象,而这个引用存放在java虚拟机栈栈帧的局部变量表中。也就是说,str只是一个引用,它指向了一个具体的对象,当str=“123”; 这句代码执行过之后,又创建了一个新的对象“123”, 而引用str重新指向了这个新的对象,原来的对象“ABC”还在内存中存在,并没有改变。

其实上面的"ABC","123"是字符串常量,按照JVM规范应该是存放在方法区的常量池里面。但是Java1.7之后HotSpot虚拟机并没有区分方法区和堆,所以,这里统一就当做是放在堆里面的吧。

原理:通过源码知道String 底层是由char数组构成,我们创建一个字符串对象的时候,其实是将字符串保存在char数组中,因为数组是引用对象,为了防止数组可变,jdk加了final修饰,但是加了final修饰的数组只是代表了引用不可变,不代表数组内容不可变,因此jdk为了真正防止不可变,又加了private修饰符。

String成员变量加是private final的,也就是初始化之后不可改变,那么引用变量value,不是一个真正的对象,value是final修饰的,也就是说final不能再指向其他数据对象。

所以String不可变,关键原因是,在后面所有的String的方法里都没有动Array里的元素,没有暴露内部成员变量,private final char value[]这一句里,private的私有访问权限的作用都比final大。而且设计师还很小心地把整个String设成final禁止继承,避免被其他人继承后破坏。所以String是不可变的关键都在底层的实现,而不是一个final

3,不可变有什么好处?

多线程下安全

类加载中体现的安全性

使用常量池可以节省空间。

经验分享 程序员 微信小程序 职场和发展