寫在前面
Java回爐系列也有十多天沒更了,雖然心里一直沒怎么放下,但是奈何有心無力。項(xiàng)目成堆問題在那,還好中秋得空,出去逛了一下午心情大好~好了,正文開始
多態(tài)是啥,能吃嗎?
學(xué)Java一般都會(huì)聽說“面向?qū)ο笕筇卣鳌保悍庋b、繼承、多態(tài)。封裝是將一個(gè)事物抽象成為一個(gè)類,這個(gè)類有自己的屬性和方法,某些屬性和功能的實(shí)現(xiàn)不會(huì)對(duì)外公開,只暴露一些可供獲取數(shù)據(jù)的方法。繼承很容易理解,就是一個(gè)類繼承另一類,這個(gè)類被稱為子類,而另一個(gè)自然就是父類了。當(dāng)然在有的書上也將父類稱為基類,將子類稱為導(dǎo)出類,看你個(gè)人喜好了,在我這統(tǒng)一稱為父、子類。好了,前面說了封裝和繼承,現(xiàn)在自然是要說多態(tài)了。多態(tài)應(yīng)當(dāng)是一種設(shè)計(jì)的思想,然后才體現(xiàn)在語言的具體實(shí)現(xiàn)。多態(tài)的核心思想是消除類型之間的耦合關(guān)系,可能你和我一樣,剛看到這句話的時(shí)候有點(diǎn)懵逼,沒關(guān)系舉個(gè)小例子:
現(xiàn)在我有個(gè)數(shù)據(jù)集,因?yàn)樵鰟h操作做的比較多,行嗎,了解數(shù)據(jù)結(jié)構(gòu)的你一定想到了鏈表。那好就用鏈表來搞起:
LinkedList<Bean> list = new LinkedList<Bean>();
可是過了一段時(shí)間,你們老大給你說需求改了,現(xiàn)在是查詢操作做的比較多。一向?qū)τ诖a效率嚴(yán)格要求的你一定能想到鏈表查起來效率有點(diǎn)低,好啊,改成ArryList也算是能接受了。
ArrayList<Bean> list = new ArrayList<Bean>();
剛改完發(fā)現(xiàn)ide里一片紅叉叉,好吧,原來是以前的方法也沒用泛型參數(shù),還得自己一個(gè)一個(gè)的去改掉。恩,改完沒兩天你們老大又來……
以上只是個(gè)帶點(diǎn)玩笑性質(zhì)的表述,在實(shí)際的操作中一般你都會(huì)這么寫:
List<Bean> list = new ArrayList<Bean>();
恩,= 右邊只要是個(gè)List接口的實(shí)現(xiàn)類就可以了,這就是解耦了。當(dāng)你采用這種寫法時(shí)好處也是顯而易見的:涉及到這個(gè)數(shù)據(jù)集的方法,你只要傳入一個(gè)List的形參就可以了,之后管你用啥實(shí)現(xiàn)(當(dāng)然了,要符合多態(tài)的規(guī)則哦),這代碼還是照常跑。
如果你是個(gè)上手Java沒多久的新人,可能會(huì)有些驚訝于這種“接口實(shí)例化”的寫法。但事實(shí)上只是Java多態(tài)的一種表現(xiàn):** Java允許父類引用指向子類對(duì)象 ** 當(dāng)然了,這句話里把父類換成接口,子類對(duì)象換成實(shí)現(xiàn)對(duì)象,也是可以的。
一些思考
寫到這樂于思考的你一定能想到一些問題:上面說了在相應(yīng)的方法里只要傳入父類就行了,那也就是說那個(gè)方法并不知道他原來的類是啥,那么他在調(diào)用對(duì)象的方法時(shí)只會(huì)調(diào)用父類的方法了?直接上代碼看看:
首先是父類
public class Parent {
public void print(){
System.out.println("I am Parent's method");
}
}
子類
public class Son extends Parent{
public void print(){
System.out.println("I am Son's method");
}
}
跑起來
public class Test {
public static void main(String[] args) {
Parent p = new Son();
Hello(p);
}
private static void Hello(Parent p) {
p.print();
}
}
運(yùn)行結(jié)果
對(duì)于這個(gè)結(jié)果我只想問一聲,憑啥啊?明明只有一個(gè)父類參數(shù)被傳進(jìn)去,他為毛能知道子類的方法啊?這是因?yàn)镴ava實(shí)現(xiàn)多態(tài)采用了一種被稱作“動(dòng)態(tài)綁定”或者“后期綁定”的牛x套路。編譯器一直不知道對(duì)象的類型,但是方法調(diào)用機(jī)制能找到正確的方法體,并加以調(diào)用。關(guān)于這個(gè)機(jī)制,現(xiàn)在暫時(shí)沒有必要太去深究。經(jīng)過以上一番探查,現(xiàn)在終于對(duì)Java的多態(tài)放了心,那么請(qǐng)開開心心的使用多態(tài)編寫你的代碼吧!
關(guān)于多態(tài)還有方法重載和方法覆蓋,我的上一篇文章第一話--從頭再來是有提到的,可以去看看。
接口與抽象類
待更新...有點(diǎn)累了,先休息了,反正這文寫給自己看的,任性點(diǎn),明天再更完。
//開更干活!
首先是語法,接口是interface,抽象是abstract。
平時(shí)在抽取基類的時(shí)候少不了用一下抽象類,你可以指定幾個(gè)抽象方法,讓你子類去實(shí)現(xiàn)這些抽象方法。當(dāng)然了你的子類也可以是一個(gè)抽象類,那么可以不實(shí)現(xiàn)這些抽象方法。當(dāng)然了,包含抽象方法的一定是抽象類, 但是不包含抽象方法的你也可以指定他是抽象類,可以有效的阻止這個(gè)類生成對(duì)象。
那么接口又是啥呢?接口是一個(gè)包含一個(gè)或者多個(gè)方法的東西,有的時(shí)候?qū)崿F(xiàn)了這個(gè)接口的類就擁有了這個(gè)接口的“特性”,而在Java中接口有的時(shí)候也被用于回調(diào)。一般的來說接口是優(yōu)于抽象類的,因?yàn)榻涌诒瘸橄箢惛橄螅耆獬祟愔g的耦合。但是這東西還是看實(shí)際情況的,有的時(shí)候接口滿天飛感覺也不是很好。再者抽象類要比接口的定制性要好,畢竟抽象類完全可以當(dāng)成一個(gè)普通的類來寫,只不過在合適的地方加上合適的抽象方法,然后讓子類去實(shí)現(xiàn)它。所以究竟采用哪個(gè)區(qū)實(shí)現(xiàn)你的多態(tài),還是看你的需求和實(shí)現(xiàn)的。
接口很多時(shí)候會(huì)被用于“回調(diào)”,比如在Android中的MVP模式就少不了回調(diào)。對(duì)于回調(diào)的理解我有寫過一篇簡(jiǎn)單的文章,感興趣可以自己去看一下。對(duì)于回調(diào),我認(rèn)為在實(shí)質(zhì)上回調(diào)就是想要在對(duì)的地方調(diào)對(duì)的方法,然后把對(duì)的數(shù)據(jù)、狀態(tài)傳遞出去,讓實(shí)現(xiàn)的類知道這個(gè)數(shù)據(jù)、狀態(tài)然后加以處理。以上是我認(rèn)為的回調(diào)的實(shí)質(zhì),之后不同的語言用什么方案解決,是函數(shù)指針還是接口,那都不是我所關(guān)心的東西了。
這一期暫時(shí)就到這了,本來還想加個(gè)內(nèi)部類上來的,后來想想還是先緩緩。這類復(fù)習(xí)類的文,代碼貼的比較少,大多是自己的一些總結(jié)性的話語……如果有人看到了,覺得不爽……只能說見諒了……