final 于 abstract 的問題
第一題:class Something{
final int f;
public void doSomething(){
System.out.println("f="+f)
}
}
第二題:
abstract class Something{
private abstract void doSomething();
}
出錯在哪里?
1)Something類在實例化的時候,會對成員變量進行初始化,f會被賦值于0,按照語法結果就是f=0,可是實際上不是。Java編譯器為了減少人犯低級錯誤,對final修飾的變量不會再進行默認初始化,而是強制要求你顯示的賦一個值。Java編譯器考慮的可真周到啊,把它自己的語法都給推翻了。這么低級的程序我是寫不出來,所以我答錯了。
2)這一題按照語法也沒錯了,可是為什么會被編譯不過去呢,說白了原因也就是Java編譯器為我們考慮太周到了,我們為什么要在抽象類中定義一個抽象方法,我們大家都知道抽象類是不能實例化,定義抽象方法就是為了定義一個子類來繼承該抽象類并實現它的抽象方法,但是題目中給定的抽象方法是private修飾的,也就是說它是不能被繼承的,也就是說我們根本不肯能寫出來一個能實現該抽象方法的類,說的更具體一點也就是這個抽象類被定義的毫無意義。Java編譯器真是太強了,連這個也被考慮到了,反正我是從來沒寫過這么低級的程序,更不會去寫出來一個毫無意義的抽象類。
一句話,這兩道題考得不是final和abstract的語法,因為完全合法,而是語義,也就是Java編程規范。
PS:關于為什么final修飾的成員變量不能被默認初始化的問題,我想了很久,終于想明白了。我們大家都知道對象初始化分為三步:
1)默認初始化
2)賦值初始化
3)構造方法初始化
如果你在類中定義的是一個普通的成員變量非final成員變量,對該類的對象初始化時,該成員變量會嚴格按照以上三步進行初始化。如果是該類的成員變量是用final修飾的,該類對象初始化時,對該成員變量的初始化按照常規也應該由這三步組成,但是由于final修飾的變量是常量,不能進行二次賦值,所以對該類型的變量初始化只能由其中一步來完成,不能出現交叉,否則會有編譯錯誤。下面是兩個可以正常編譯、運行的寫法:








































1)按照常理會對f默認初始化為0;
2)程序中并沒有出現交叉,也就是說并沒有進行二次賦值的可能。
但是編譯器為什么不放過它呢?
現在讓我們來假設一下如果不給f變量不顯示的賦一個值,它一定會被初始化為0,按照final的定義一旦被初始化一個值后就不能修改了,也就是說f的值只能是0了。再想想當初我們為什么要定義一個final修飾的常量,難道僅僅就是為了得到一個默認的不能修改的初始值嗎,這恐怕有違我們當初定義final變量的真正意愿,那么我定義這個final變量又有何意義呢。所以在對對象進行初始化時,發現對象的成員是用final修飾的就會查看它是否被顯示的賦了值,如果沒有就會不能正常編譯。這也是Java編程規范中為什么要強制對final變量進行顯示賦值的真正原因。同樣的道理在abstract類里面定義private abstract方法,這個又有何意義呢?Java中把那些符合語法但不符合常規的用法定義成了規范,我想這也是Java為什么會有編程規范的原因吧,呵呵,扯遠了。。。
posted on 2008-08-14 21:39 gdufo 閱讀(563) 評論(0) 編輯 收藏 所屬分類: JAVA 基礎