0 l' ^3 |: ]6 M P! G C) us = new String("Initial Value"); - L' H6 X) m R后者每次都会调用构造器,生成新对象,性能低下且内存开销大,并且没有意义,因为String对象不可改变,所以对于内容相同的字符串,只要一个String对象来表示就可以了。也就说,多次调用上面的构造器创建多个对象,他们的String类型属性s都指向同一个对象。4 ]7 }- S" `' X6 l& D
! [: R& f& B; n7 D& `9 U9 O9 Y
上面的结论还基于这样一个事实:对于字符串常量,如果内容相同,Java认为它们代表同一个String对象。而用关键字new调用构造器,总是会创建一个新的对象,无论内容是否相同。 ) ^/ z: A& C I, B5 r8 E! [% N0 Z6 f$ Q, g. `% M7 a. x$ d. R
至于为什么要把String类设计成不可变类,是它的用途决定的。其实不只String,很多Java标准类库中的类都是不可变的。在开发一个系统的时候,我们有时候也需要设计不可变类,来传递一组相关的值,这也是面向对象思想的体现。不可变类有一些优点,比如因为它的对象是只读的,所以多线程并发访问也不会有任何问题。当然也有一些缺点,比如每个不同的状态都要一个对象来代表,可能会造成性能上的问题。所以Java标准类库还提供了一个可变版本,即StringBuffer。 3 I8 e) ^1 R J& D8 e! o8 }3 ^3 W6 s# T" T- E
问题四:final关键字到底修饰了什么?. U. S1 i1 j9 X& V# H; y5 d
9 A! C7 H+ _! Lfinal使得被修饰的变量"不变",但是由于对象型变量的本质是“引用”,使得“不变”也有了两种含义:引用本身的不变,和引用指向的对象不变。 3 ]- ]1 G4 w/ c3 y2 b& u# ~; G' H7 g0 u# B2 g" K
引用本身的不变: 4 ?. f" S* X e: m' ?; T# |6 v+ i0 c: ^. e& ?5 w8 L0 ]; m
final StringBuffer a=new StringBuffer("immutable"); , b# Z7 R9 z$ E& w5 q+ h* Rfinal StringBuffer b=new StringBuffer("not immutable"); . H0 h& \* C5 q" o0 x! `- O. H
a=b;//编译期错误 ' U- g0 F/ |; L5 U O, G7 |; p# W引用指向的对象不变:) g0 m4 b1 Z8 w. w w0 W
" `/ s m0 g7 y/ F9 H% ]" wfinal StringBuffer a=new StringBuffer("immutable"); 8 \2 K i. ^- m% oa.append(" broken!"); //编译通过 / F, M) e( @" h5 M
可见,final只对引用的“值”(也即它所指向的那个对象的内存地址)有效,它迫使引用只能指向初始指向的那个对象,改变它的指向会导致编译期错误。至于它所指向的对象的变化,final是不负责的。这很类似==操作符:==操作符只负责引用的“值”相等,至于这个地址所指向的对象内容是否相等,==操作符是不管的。 理解final问题有很重要的含义。许多程序漏洞都基于此----final只能保证引用永远指向固定对象,不能保证那个对象的状态不变。在多线程的操作中,一个对象会被多个线程共享或修改,一个线程对对象无意识的修改可能会导致另一个使用此对象的线程崩溃。一个错误的解决方法就是在此对象新建的时候把它声明为final,意图使得它“永远不变”。其实那是徒劳的。( Q5 d$ g9 X3 z( f3 `+ o! p8 O" |6 w8 ^! |
3 V0 ?1 f. N/ o8 J" D; Q/ C/ \
问题五:到底要怎么样初始化! ' H+ K' Y/ o. ]% Y, i . l5 Y( F1 v! Q1 n2 ]6 Q7 i2 `" E本问题讨论变量的初始化,所以先来看一下Java中有哪些种类的变量。 `; A& @. r9 I6 Y8 G" n2 S4 n. s2 M% X5 l
1. 类的属性,或者叫值域5 ~1 N( o! C9 k" A' a. L: @
: [$ J2 F# \! k; ?% ?
2. 方法里的局部变量0 H V* j; U- L# X% r Q1 F% t+ W
( b) T1 b# C3 C$ {
3. 方法的参数$ O1 s5 F/ P; Q9 U8 Y
8 k$ b2 w* p+ i y
对于第一种变量,Java虚拟机会自动进行初始化。如果给出了初始值,则初始化为该初始值。如果没有给出,则把它初始化为该类型变量的默认初始值。6 E* P$ Y# N5 z) I( ?% }
, i" g# d6 Z Y8 @$ U5 K2 A" [
int类型变量默认初始值为0 * m& z) J& O7 I% W9 _$ ]/ j ' ]' s* J7 P! v0 E7 H$ d/ Kfloat类型变量默认初始值为0.0f6 p4 W. e5 \7 o$ _
" b- s; }$ t! Z8 M) u9 X
double类型变量默认初始值为0.0 4 \5 p4 T6 E1 Y7 D% b/ S+ \6 x& n9 e
boolean类型变量默认初始值为false' F9 Q0 G; S& u4 e