假設現在有7個類,分別如下: 1. 動物(Animal)抽象類 2. 哺乳動物(Mammal)抽象類 繼承動物類 3. 爬行動物(Reptile)抽象類 繼承動物類 4. 老虎(Tiger) 繼承爬行動物類 5. 蛇類(Snake) 繼承爬行動物類 6. 兔子(Rabbit) 繼承哺乳動物類 7. 農夫(Farmer)農夫可以喂養Animal
動物都會行走,喝水,代碼如下
abstract class Animal{ public abstract void move(); public abstract void drink();}農夫沒有繼承任何類,但農夫可以給動物喂水喝,而不關心給什么動物喂水喝,也不關心動物們從哪里來。
public class farmer{ public void bringWater(String destination){ System.out.println("Farmer bring water to " + destination +"."); } public void feedWater(Animal animal, String destination){ this.bringWater(destination); animal.move(destination); animal.drink(); }}農夫依次去三個地方給三只動物喂水,執行Farmer喂水代碼
public void f(){ Tiger tiger = new Tiger(); Snake snake = new Snake(); Rabbit rabbit = new Rabbit(); Farmer farmer = new Farmer(); farmer.feedWater(tiger, room); farmer.feedWater(snake, grassland); farmer.feedWater(rabbit, kichen);}執行結果:
[java] Farmer bring water to room. [java] Tiger moved to room. [java] Tiger down to drink water. [java] Farmer bring water to grassland. [java] Snake moved to grassland. [java] Snake stretched his tongue to drink water. [java] Farmer bring water to kichen. [java] Rabbit moved to kichen. [java] Rabbit put out it's tongue and drink.如果老虎、蛇、兔子沒有繼承抽象類來重寫同一個抽象方法,多態就不能實現 這樣的話,農夫類就要根據參數類型重載多個feedwater()方法,像這樣:
feedwater(Tiger tiger, String destination);feedwater(Snake snake, String destination);...Tiger、Snake、Rabbit繼承了Raptile、Mammer抽象類,而Raptile、Mammer類繼承基類Animal抽象類,所以Tiger、Snake、Rabbit都向上轉型為Animal類,例如可以把農夫喂水的執行代碼寫成下面這樣:
public void f(){ Animal tiger = new Tiger(); Animal snake = new Snake(); Animal rabbit = new Rabbit(); Farmer farmer = new Farmer(); farmer.feedWater(tiger, room); farmer.feedWater(snake, grassland); farmer.feedWater(rabbit, kichen);}既然抽象類與接口都能實現多態,那什么時候才需要使用接口呢?
假設現在農夫學會了一個新方法,帶動物讓Tiger和Snake捕食,需要給Tiger、Snake加一個捕食方法hunt(),Rabbit則不需要此方法。 但從以上類中發現,Snake、Tiger繼承于Raptile、Mammer抽象類,Mammer的子類中有Rabbit類,則hunt()方法不能直接寫入Animal類中,因為寫在Animal類中,Animal的所有方法將會直接繼承到子類中,由于Rabbit類用不上hunt()方法,則會造成資源浪費。 現在考慮幾種方案: 1. 直接將hunt()方法寫在各肉食動物的類中 若這樣做,就不能實現多態,每個類中的hunt()方法只能由類對象
進行調用,像這樣:
此時農夫類像這樣,需要對Tiger、Snake類方法重載:
class Farmer{ public void bringWater(String destination){ System.out.println("Farmer bring water to " + destination + "."); } public void bringAnimal(Animal a,String destination){ System.out.println("Farmer bring " + a.getName() + " to " + destination + "."); } public void feedWater(Animal animal, String destination){ this.bringWater(destination); animal.move(destination); animal.drink(); } public void feedAnimal(Tiger tiger , Animal animal){ this.bringAnimal(animal,"Feeding Room"); tiger.move("Feeding Room"); tiger.hunt(animal); } public void feedAnimal(Snake snake, Animal animal){ snake.bringAnimal(animal,"Feeding Room"); snake.move("Feeding Room"); snake.hunt(animal); } }若有很多會捕食的動物,將需要大量重載,所以這個方案不可以取。 2. 增加 肉食動物 抽象類 如果是加入肉食動物類與非肉食動物類,將會使得類族圖復雜化,因為肉食動物中也有不會捕獵的動物。
這個時候就需要用到接口了。
定義好了接口之后,直接由Tiger、Snake遵循這個接口,需要用到implements關鍵字:
此時接口實現了多態。 接口也成為Java中的多重繼承,在導出類中,如果是從一個非接口的類繼承,那只能繼承這一個類,其余的基元素都必須是接口,需要把所有的接口都置于implements關鍵字之后,用逗號將它們隔開。
一、明明可以在類中直接寫所需的方法,為什么還要多寫一個接口(或抽象類)? 1. 減少代碼的書寫(上邊分析的代碼重載) 2. 提高了代碼的可維護性和擴展性。 3. 在團隊合作中,代碼的規范性
二、抽象類和接口都差不多,在什么時候才選擇使用接口? 1. 在當前類族中不是必須的(例如Tuger需要而Rabbit不需要)的方法時 2. 不同類族的多個類需要實現同樣的方法時(接口)
新聞熱點
疑難解答