Java中的String为什么被设计成不可变类型?
首先,我们看一下java中String的源码
可以发现String其实就是由value[] 数组拼接而成,且value是被final修饰的。
1、当final修饰类时,这个类是不可继承的。
2、当final修饰属性时,那么这个属性是不可修改的。
若final修饰的是基本类型(8种),那么它的值是不可修改的。
如果是数组或引用类型,那么仅仅是无法改变引用所指向的地址,而内存地址上的值是可以改变的。
例:
public void try(){
final char[] value = new char[]{'a','b','c'};
value[0] = 'd';
System.out.println(value);
}
OUTPUT:dbc
所以是可以改变value的值。
那么String为什么要被设计成不可变类型呢?
String能被设计成不可变类型的一个重要前是因为它是编程语言里面使用频率最高的一种类型。不可变类型带来的好处,体现在四个方面,分别是:安全,缓存,同步和性能。
安全
1、无法被继承。私有方法无法被重写。可以保证语义的统一。
2、每次对String的操作都会产生一个新的对象。(在使用hashset或者Hashmap时,最好用不可变类型作为key)
3、线程安全。由于String类型的不可变性,使得String对象可以安全的在多个线程之间传递和访问,也就是说你在多线程中是不能改变字符串本身的值,而是在堆里面新创建一个字符串然后操作。当然如果没有final修饰,你是可以改变这个变量的引用地址,也就是说你可以把新生成的内存引用覆盖原来的变量引用,但这里仅仅是引用,并不是变量的值。这一点要注意。
例子:
String a = "123";
String b = "123";
String c = new String("123");
String d = new String("123");
System.out.println(a == b); //true
System.out.println(b == c); //false
System.out.println(c == d); //false
这里要引出String常量池的概念。
字符串常量池(String pool, String intern pool, String保留池) 是Java堆内存中一个特殊的存储区域(位于方法区method area), 当创建一个String对象时,假如此字符串值已经存在于常量池中,则不会创建一个新的对象,而是引用已经存在的对象。而且常量池中的对象不会轻易地被垃圾回收。
所以a和b指向的是常量池中的同一个对象 “123” 。引用c 和 d是指向各自在堆上创建的对象,而“==”符号判断的是引用所指向的内存地址是否相同,简而言之就是判断是否指向同一个对象。
ps:仅作为本人学习过程中一些记录,若有错误还望指正。