它设置为初始值,应当 这样做: public class Demo { private String s; ... 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 只能保证引用永远指向
固定 对象,
不能保证那个对象的
状态不变。在多线程的操作中,一个对象会被多个线程
共享或修 改, 一个线程对对象无
意识的修改可能会导致另一个使用此对象的线程崩溃。 一个错误的解 决方法就是在此对象新建的时候把它声明为 final,意图使得它“永远不变” 。其实那是徒劳 的。 问题五:到底要
怎么样初始化! 本问题讨论变量的初始化,所以先来看一下 Java 中有
哪些种类的变量。 1. 类的属性,或者叫值域 2. 方法里的局部变量 3. 方法的参数 对于第一种变量, Java 虚拟机会自动
进行初始化。 如果给出了初始值, 则初始化为该初始值。 如果没有给出,则把它初始化为该类型变量的默认初始值。 int 类型变量默认初始值为 0 float 类型变量默认初始值为 0.0f double 类型变量默认初始值为 0.0 boolean
类型变量默认初始值为 false char 类型变量默认初始值为 0(ASCII 码) long 类型变量默认初始值为 0
所有对象引用类型变量默认初始值为 null,即不指向任何对象。
注意数组本身也是对象, 所以没有初始化的数组引用在自动初始化后其值也是 null。 对于两种不同的类属性,static
属性与 instance 属性,初始化的时机是不同的。instance 属性 在创建实例的时候初始化,static 属性在类加载,也就是第一次用到这个类的时候初始化, 对于后来
的实例的创建,不再次进行初始化。这
个问题会在以
后的系列中进行
详细讨论。 对于第二种变量,必须明确地进行初始化。如果再没有初始化之前就试图
使用它,
编译器会 抗议。如果初始
化的语句在 try 块中或 if 块中,也
必须要让它在第
一次使用前一定能够得到 赋值。也就是说,把初始化语句放在只有 if 块的条件判断语句中编译器也会抗议,因为执 行的时候可能不符合 if 后面的
判断条件,如此一来初始化语句就不会被执行了,这就违反 了局部变量使用前必须初始化的规定。但如果在 else 块中也有初始化语句,就
可以通过编
译, 因为无论如何, 总有至少一条初始化语句会被执行, 不会发生使用前未被初始化的事情。 对于 try-catch 也是一样,如果只有在 try 块里