...
public Demo {
s = "Initial Value";
}
...
}
而非
s = new String("Initial Value");
后者每次都会调用构造器,生成新对象,性能低下且内存开销大,并且没有意义,因为
String 对象不可改变,所以对于内容相同的字符串,只要一个 String 对象来表示就可以了。
也就说,多次调用上面的构造器创建多个对象,他们的 String 类型属性 s 都指向同一个对
象。
上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java 认为它们代表
同一个 String 对象。而用关键字 new 调用构造器,总是会创建一个新的对象,无论内容是
否相同。
至于为什么要把 String 类设计成不可变类,是它的用途决定的。其实不只 String,很多
Java 标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可
变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因
为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如
每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以 Java 标准类库还提
供了一个可变版本,即 StringBuffer
。
问题四:final
关键字到底修饰了什么?
final 使得被修饰的变量"不变"
“
”
“
”
,但是由于对象型变量的本质是 引用 ,使得 不变 也有
了两种含义:引用本身的不变,和引用指向的对象不变。
引用本身的不变:
final StringBuffer a=new StringBuffer("immutable");
final StringBuffer b=new StringBuffer("not immutable");
a=b;//
编译期错误
引用指向的对象不变:
final StringBuffer a=new StringBuffer("immutable");
a.append(" broken!"); //
编译通过
可见,final
“ ”
只对引用的 值 (也即它所指向的那个对象的内存地址)有效,它迫使引用只
能指向初始指向的那个对象,改变它的指向会导致编译期错误。至于它所指向的对象的变
化,final 是不负责的。这很类似==操作符:==
“ ”
操作符只负责引用的 值 相等,至于这个
地址所指向的对象内容是否相等,==
操作符是不管的。
理解 final 问题有很重要的含义。许多程序漏洞都基于此----final 只能保证引用永远指向固
定对象,不能保证那个对象的状态不变。在多线程的操作中,一个对象会被多个线程共享
或修改,一个线程对对象无意识的修改可能会导致另一个使用此对象的线程崩溃。一个错