01 什么是不可变性
不可变是指对象的属性被赋值后就不能变了
也就是说String类的属性被构造方法初始化之后就没有其他的办法进行修改了
02 String是如何被设计为不可变的
在创建对象的时候只能通过构造方法的形式,不能通过set方法
当构造方法是空时,对应的构造方法源码是下面的,等于是 空的字符串
当使用带参数的构造方法时,带参构造方法源码
上面的代码可以看到都是把构造方法中的参数给了String类的char类型的数组
1 char类型的数组是private的,不能在类外部调用修改
2 char类型的数组是final的,引用地址不能变
3 没有提供set()方法来修改字符串的值
4 类声明为final不允许继承 子类就不能修改
也就是说String类的属性被构造方法初始化之后就没有其他的办法进行修改了
03 为什么被设计为不可变
(1) 字符串常量池的需要
只有当字符串是不可变的,字符串池才有可能实现。因为多个字符串引用都指向常量池中的同一个字符串常量对象。但如果字符串是可变的,其中有一个引用改变了它的值,那么其它引用变量的对象值也会一起改变 ,就会引起错误
(2) hashcode缓存的需要
因为字符串不可变,所以在它创建时hashcode就被缓存了,不需要重新计算。这就使得字符串很适合作为HashMap或hashSet中的key,效率高。字符串处理速度要快过其它的键对象
(3) 多线程安全
多线程中,可变对象的值很可能被其他线程改变,造成不可预期的结果。而不可变的String可以自由在多个线程之间共享,不需要同步处理
(4) 安全问题
如果字符串是可变的,那么会引起很严重的安全问题。如,数据库的用户名、密码都是以String的形式传入来获得数据库的连接,或者在 socket 编程中,主机名和端口都是以字符串的形式传入。因为字符串是不可变的,所以它的值是不可改变的,否则黑客们可以钻到空子,改变字符串指向的对象的值,造成安全漏洞
类加载器要用到字符串,不可变性提供了安全性,以便正确的类被加载。譬如你想加载 java.sql.Connection 类,而这个值被改成了 myhacked.Connection ,那么会对你的数据库造成不可知的破坏
安全首要原因是安全,不仅仅体现在你的应用中,而且在JDK中,Java的类装载机制通过传递的参数(通常是类名)加载类,这些类名在类路径下,想象一下,假设String是可变的,一些人通过自定义类装载机制分分钟黑掉应用。如果没有了安全,Java不会走到今天
04 体现不可变性质
两个指向指向同一个字面值 其中一个进行修改 另外一个还是以前的值
输出
a
b
使用replace()等时 生成新的自传 以前的字符串不会变
输出
bbc
问题
这段代码执行后 原始string对象中的内容变了吗
没有
String被设计成不可变类,它的所有对象都是不可变对象 string原先指向"a"对象,然后对string进行了+操作 这时string不再指向原来那个对象了,而指向了"ab"对象,原来那个对象还存在于内存之中,只是string这个引用变量不再指向它了