第二話 再探多型

xiasuhuei321發表於2017-12-13

寫在前面

Java回爐系列也有十多天沒更了,雖然心裡一直沒怎麼放下,但是奈何有心無力。專案成堆問題在那,還好中秋得空,出去逛了一下午心情大好~好了,正文開始

多型是啥,能吃嗎?

學Java一般都會聽說“物件導向三大特徵”:封裝、繼承、多型。封裝是將一個事物抽象成為一個類,這個類有自己的屬性和方法,某些屬性和功能的實現不會對外公開,只暴露一些可供獲取資料的方法。繼承很容易理解,就是一個類繼承另一類,這個類被稱為子類,而另一個自然就是父類了。當然在有的書上也將父類稱為基類,將子類稱為匯出類,看你個人喜好了,在我這統一稱為父、子類。好了,前面說了封裝和繼承,現在自然是要說多型了。多型應當是一種設計的思想,然後才體現在語言的具體實現。多型的核心思想是消除型別之間的耦合關係,可能你和我一樣,剛看到這句話的時候有點懵逼,沒關係舉個小例子:

舉個栗子

現在我有個資料集,因為增刪操作做的比較多,行嗎,瞭解資料結構的你一定想到了連結串列。那好就用連結串列來搞起:

LinkedList<Bean> list = new LinkedList<Bean>();
複製程式碼

可是過了一段時間,你們老大給你說需求改了,現在是查詢操作做的比較多。一向對於程式碼效率嚴格要求的你一定能想到連結串列查起來效率有點低,好啊,改成ArryList也算是能接受了。

ArrayList<Bean> list = new ArrayList<Bean>();
複製程式碼

剛改完發現ide裡一片紅叉叉,好吧,原來是以前的方法也沒用泛型引數,還得自己一個一個的去改掉。恩,改完沒兩天你們老大又來……

以上只是個帶點玩笑性質的表述,在實際的操作中一般你都會這麼寫:

List<Bean> list = new ArrayList<Bean>();
複製程式碼

恩,= 右邊只要是個List介面的實現類就可以了,這就是解耦了。當你採用這種寫法時好處也是顯而易見的:涉及到這個資料集的方法,你只要傳入一個List的形參就可以了,之後管你用啥實現(當然了,要符合多型的規則哦),這程式碼還是照常跑。

如果你是個上手Java沒多久的新人,可能會有些驚訝於這種“介面例項化”的寫法。但事實上只是Java多型的一種表現:** Java允許父類引用指向子類物件 ** 當然了,這句話裡把父類換成介面,子類物件換成實現物件,也是可以的。

一些思考

寫到這樂於思考的你一定能想到一些問題:上面說了在相應的方法裡只要傳入父類就行了,那也就是說那個方法並不知道他原來的類是啥,那麼他在呼叫物件的方法時只會呼叫父類的方法了?直接上程式碼看看: 首先是父類

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();
	}
}
複製程式碼

執行結果

結果

對於這個結果我只想問一聲,憑啥啊?明明只有一個父類引數被傳進去,他為毛能知道子類的方法啊?這是因為Java實現多型採用了一種被稱作“動態繫結”或者“後期繫結”的牛x套路。編譯器一直不知道物件的型別,但是方法呼叫機制能找到正確的方法體,並加以呼叫。關於這個機制,現在暫時沒有必要太去深究。經過以上一番探查,現在終於對Java的多型放了心,那麼請開開心心的使用多型編寫你的程式碼吧!

關於多型還有方法過載和方法覆蓋,我的上一篇文章第一話--從頭再來是有提到的,可以去看看。

介面與抽象類

待更新...有點累了,先休息了,反正這文寫給自己看的,任性點,明天再更完。 //開更幹活! 首先是語法,介面是interface,抽象是abstract。

平時在抽取基類的時候少不了用一下抽象類,你可以指定幾個抽象方法,讓你子類去實現這些抽象方法。當然了你的子類也可以是一個抽象類,那麼可以不實現這些抽象方法。當然了,包含抽象方法的一定是抽象類, 但是不包含抽象方法的你也可以指定他是抽象類,可以有效的阻止這個類生成物件。

那麼介面又是啥呢?介面是一個包含一個或者多個方法的東西,有的時候實現了這個介面的類就擁有了這個介面的“特性”,而在Java中介面有的時候也被用於回撥。一般的來說介面是優於抽象類的,因為介面比抽象類更抽象,完全解除了類之間的耦合。但是這東西還是看實際情況的,有的時候介面滿天飛感覺也不是很好。再者抽象類要比介面的定製性要好,畢竟抽象類完全可以當成一個普通的類來寫,只不過在合適的地方加上合適的抽象方法,然後讓子類去實現它。所以究竟採用哪個區實現你的多型,還是看你的需求和實現的。

介面很多時候會被用於“回撥”,比如在Android中的MVP模式就少不了回撥。對於回撥的理解我有寫過一篇簡單的文章,感興趣可以自己去看一下。對於回撥,我認為在實質上回撥就是想要在對的地方調對的方法,然後把對的資料、狀態傳遞出去,讓實現的類知道這個資料、狀態然後加以處理。以上是我認為的回撥的實質,之後不同的語言用什麼方案解決,是函式指標還是介面,那都不是我所關心的東西了。

這一期暫時就到這了,本來還想加個內部類上來的,後來想想還是先緩緩。這類複習類的文,程式碼貼的比較少,大多是自己的一些總結性的話語……如果有人看到了,覺得不爽……只能說見諒了……

相關文章