我現(xiàn)在才發(fā)現(xiàn)我那天遇到的兩道面試題不但不變態(tài)而且還很有意義
Posted on 2008-03-20 23:46 flustar 閱讀(3609) 評論(24) 編輯 收藏 所屬分類: 想說的話第一題:
class Something{
final int f;
public void doSomething(){
System.out.println("f="+f)
}
}
第二題:
abstract class Something{
private abstract void doSomething();
}
為什么毫無意義?我先給出我最初的答案
1)f=0
2)沒有錯誤
這是我面試的時候?qū)懙拇鸢福?dāng)時以為沒錯,因?yàn)檫@完全符合java的語法
1)Something類在實(shí)例化的時候,會對成員變量進(jìn)行初始化,f會被賦值于0,按照語法結(jié)果就是f=0,可是實(shí)際上不是。Java編譯器為了減少人犯低級錯誤,對final修飾的變量不會再進(jìn)行默認(rèn)初始化,而是強(qiáng)制要求你顯示的賦一個值。Java編譯器考慮的可真周到啊,把它自己的語法都給推翻了。這么低級的程序我是寫不出來,所以我答錯了。
2)這一題按照語法也沒錯了,可是為什么會被編譯不過去呢,說白了原因也就是Java編譯器為我們考慮太周到了,我們?yōu)槭裁匆诔橄箢愔卸x一個抽象方法,我們大家都知道抽象類是不能實(shí)例化,定義抽象方法就是為了定義一個子類來繼承該抽象類并實(shí)現(xiàn)它的抽象方法,但是題目中給定的抽象方法是private修飾的,也就是說它是不能被繼承的,也就是說我們根本不肯能寫出來一個能實(shí)現(xiàn)該抽象方法的類,說的更具體一點(diǎn)也就是這個抽象類被定義的毫無意義。Java編譯器真是太強(qiáng)了,連這個也被考慮到了,反正我是從來沒寫過這么低級的程序,更不會去寫出來一個毫無意義的抽象類。
一句話,這兩道題考得不是final和abstract的語法,因?yàn)橥耆戏ǎ钦Z義,也就是Java編程規(guī)范。
PS:關(guān)于為什么final修飾的成員變量不能被默認(rèn)初始化的問題,我想了很久,終于想明白了。我們大家都知道對象初始化分為三步:
1)默認(rèn)初始化
2)賦值初始化
3)構(gòu)造方法初始化
如果你在類中定義的是一個普通的成員變量非final成員變量,對該類的對象初始化時,該成員變量會嚴(yán)格按照以上三步進(jìn)行初始化。如果是該類的成員變量是用final修飾的,該類對象初始化時,對該成員變量的初始化按照常規(guī)也應(yīng)該由這三步組成,但是由于final修飾的變量是常量,不能進(jìn)行二次賦值,所以對該類型的變量初始化只能由其中一步來完成,不能出現(xiàn)交叉,否則會有編譯錯誤。下面是兩個可以正常編譯、運(yùn)行的寫法:
/**
*
* @author <a href="mailto:flustar2008@163.com">flustar</a>
* @version 1.0 Creation date: Mar 22, 2008 7:18:18 PM
*/
public class TestFinal {
final int f=1;
public void doSomething() {
System.out.println("f=" + f);
}
public static void main(String args[]) {
TestFinal test = new TestFinal();
test.doSomething();
}
}
和
/**
*
* @author <a href="mailto:flustar2008@163.com">flustar</a>
* @version 1.0 Creation date: Mar 22, 2008 7:18:18 PM
*/
public class TestFinal {
final int f;
public TestFinal(){
f=1;
}
public void doSomething() {
System.out.println("f=" + f);
}
public static void main(String args[]) {
TestFinal test = new TestFinal();
test.doSomething();
}
}
下面再讓我們回過頭來看看下面這個程序它完全符合Java的語法:
class Something{
final int f;
public void doSomething(){
System.out.println("f="+f)
}
}
為什么說它完全符合語法:
1)按照常理會對f默認(rèn)初始化為0;
2)程序中并沒有出現(xiàn)交叉,也就是說并沒有進(jìn)行二次賦值的可能。
但是編譯器為什么不放過它呢?
現(xiàn)在讓我們來假設(shè)一下如果不給f變量不顯示的賦一個值,它一定會被初始化為0,按照final的定義一旦被初始化一個值后就不能修改了,也就是說f的值只能是0了。再想想當(dāng)初我們?yōu)槭裁匆x一個final修飾的常量,難道僅僅就是為了得到一個默認(rèn)的不能修改的初始值嗎,這恐怕有違我們當(dāng)初定義final變量的真正意愿,那么我定義這個final變量又有何意義呢。所以在對對象進(jìn)行初始化時,發(fā)現(xiàn)對象的成員是用final修飾的就會查看它是否被顯示的賦了值,如果沒有就會不能正常編譯。這也是Java編程規(guī)范中為什么要強(qiáng)制對final變量進(jìn)行顯示賦值的真正原因。同樣的道理在abstract類里面定義private abstract方法,這個又有何意義呢?Java中把那些符合語法但不符合常規(guī)的用法定義成了規(guī)范,我想這也是Java為什么會有編程規(guī)范的原因吧,呵呵,扯遠(yuǎn)了。。。
class Something{
final int f;
public void doSomething(){
System.out.println("f="+f)
}
}
第二題:
abstract class Something{
private abstract void doSomething();
}
為什么毫無意義?我先給出我最初的答案
1)f=0
2)沒有錯誤
這是我面試的時候?qū)懙拇鸢福?dāng)時以為沒錯,因?yàn)檫@完全符合java的語法
1)Something類在實(shí)例化的時候,會對成員變量進(jìn)行初始化,f會被賦值于0,按照語法結(jié)果就是f=0,可是實(shí)際上不是。Java編譯器為了減少人犯低級錯誤,對final修飾的變量不會再進(jìn)行默認(rèn)初始化,而是強(qiáng)制要求你顯示的賦一個值。Java編譯器考慮的可真周到啊,把它自己的語法都給推翻了。這么低級的程序我是寫不出來,所以我答錯了。
2)這一題按照語法也沒錯了,可是為什么會被編譯不過去呢,說白了原因也就是Java編譯器為我們考慮太周到了,我們?yōu)槭裁匆诔橄箢愔卸x一個抽象方法,我們大家都知道抽象類是不能實(shí)例化,定義抽象方法就是為了定義一個子類來繼承該抽象類并實(shí)現(xiàn)它的抽象方法,但是題目中給定的抽象方法是private修飾的,也就是說它是不能被繼承的,也就是說我們根本不肯能寫出來一個能實(shí)現(xiàn)該抽象方法的類,說的更具體一點(diǎn)也就是這個抽象類被定義的毫無意義。Java編譯器真是太強(qiáng)了,連這個也被考慮到了,反正我是從來沒寫過這么低級的程序,更不會去寫出來一個毫無意義的抽象類。
一句話,這兩道題考得不是final和abstract的語法,因?yàn)橥耆戏ǎ钦Z義,也就是Java編程規(guī)范。
PS:關(guān)于為什么final修飾的成員變量不能被默認(rèn)初始化的問題,我想了很久,終于想明白了。我們大家都知道對象初始化分為三步:
1)默認(rèn)初始化
2)賦值初始化
3)構(gòu)造方法初始化
如果你在類中定義的是一個普通的成員變量非final成員變量,對該類的對象初始化時,該成員變量會嚴(yán)格按照以上三步進(jìn)行初始化。如果是該類的成員變量是用final修飾的,該類對象初始化時,對該成員變量的初始化按照常規(guī)也應(yīng)該由這三步組成,但是由于final修飾的變量是常量,不能進(jìn)行二次賦值,所以對該類型的變量初始化只能由其中一步來完成,不能出現(xiàn)交叉,否則會有編譯錯誤。下面是兩個可以正常編譯、運(yùn)行的寫法:








































1)按照常理會對f默認(rèn)初始化為0;
2)程序中并沒有出現(xiàn)交叉,也就是說并沒有進(jìn)行二次賦值的可能。
但是編譯器為什么不放過它呢?
現(xiàn)在讓我們來假設(shè)一下如果不給f變量不顯示的賦一個值,它一定會被初始化為0,按照final的定義一旦被初始化一個值后就不能修改了,也就是說f的值只能是0了。再想想當(dāng)初我們?yōu)槭裁匆x一個final修飾的常量,難道僅僅就是為了得到一個默認(rèn)的不能修改的初始值嗎,這恐怕有違我們當(dāng)初定義final變量的真正意愿,那么我定義這個final變量又有何意義呢。所以在對對象進(jìn)行初始化時,發(fā)現(xiàn)對象的成員是用final修飾的就會查看它是否被顯示的賦了值,如果沒有就會不能正常編譯。這也是Java編程規(guī)范中為什么要強(qiáng)制對final變量進(jìn)行顯示賦值的真正原因。同樣的道理在abstract類里面定義private abstract方法,這個又有何意義呢?Java中把那些符合語法但不符合常規(guī)的用法定義成了規(guī)范,我想這也是Java為什么會有編程規(guī)范的原因吧,呵呵,扯遠(yuǎn)了。。。