在JDK中,不变模式有很多应用,如Integer,Long等所有元数据类的包装类,当然,最典型的就是String类了。
对于String类而言,内部是这样定义的:public final class String 是一个被final关键字修饰的类,我们来看看上面说到final关键字的作用,这就意味着:
很明显,当然是为了安全呀
先看到String源码中的如何赋值的
- /** The value is used for character storage. */
- private final char value[];
注释部分说的很明白,它是用一个final的字符数组来储存字符串的。
虽然value是不可变,但只是value这个引用地址不可变。但是Array数组是可变!!!
因为Array变量只是stack上的一个引用,数组的本体结构在堆。如图:
String类里的value用final修饰,只是说stack里的这个叫value的引用地址不可变。没有说堆里array本身数据不可变。
eg:
- final char value[]={'a','b','c'};
- char value2[]={'d'};
- //value=value2; //编译器报错,因为用了final修饰
- value[0]='d';
- for (char v : value) {
- System.out.print(v);//输出 dbc
- }
很明显,这个value虽然被声明成final,但是如果value溢出了,就很容被修改了。
幸好,在设计String 的时候,value不仅是final的,而且还是private的,并且在后面所有String的方法里很小心的没有去动Array里的元素,没有暴露内部成员字段。
再者,String基本约定中最重要的一条是immutable。String是几乎每个类都会使用的类,所以保护String的不可变很重要,所以整个String类被设成final,从而实现禁止继承,避免被其他人继承后破坏。
假如String没有声明为final, 那么String的子类就有可能是被复写为mutable的,这样就打破了成为共识的基本约定。并且会造成不可想象的后果,
如,Hashmap之类的集合的key值,mutable的String有非常大的风险,可能会破坏了Hashmap键值的唯一性等。
安全之外,还可以涉及到性能方面:
String在堆中维护着一个字符串常量池。如字符串one和two都赋值为"something"。它们其实都指向同一个内存地址。
- String one = "someString";
- String two = "someString";
这样在大量使用字符串的情况下,可以节省内存空间,提高效率。
More:
Why String is Immutable or Final in Java?
来源: http://www.cnblogs.com/jachin01/p/7932920.html