爲什麼有抽象類
如果把類的繼承結構看成一個金字塔,毫無疑問,位於金字塔頂端的父類更具有通用性,也會更加抽象,我們通常使用這個類來作爲派生其他類的基類,而不是直接作爲實例類。
比如,Tiger類和Rabbit類都是屬於Animal類的一個子類,我們可以給他們一個getDescription()方法來對他們的特點進行描述,在Tiger類和Rabbit類中對於這個方法的實現很簡單,只需要返回一個帶有具體屬性的字符串即可,比如:吃肉的小腦斧,吃素的小兔紙。但是Animal類中我們並不能確定這個動物是吃素還是吃肉,具體的實現需要看它的子類,這裏我們可以讓Animal類的這個方法返回一個空的字符串,當然,我們還有一個更好的做法,就是給這個方法加上abstract關鍵字,這樣我們就可以不用對這個方法進行實現了。
public abstract String getDescription();
爲了提高程序的清晰度和代碼的可讀性,包含一個或多個抽象方法的類本身必須被聲明爲抽象的,也就是我們所說的抽象類
抽象類的特點
- 抽象類除了抽象方法以外,還可以包含具體數據和具體方法。比如,Animal類還保存着名字和一個返回名字的具體
public abstract class Animal { private String name; public Animal(String name) { this.name = name; } public abstract String getDescription(); public String getName() { return name; } }
抽象方法相當於一個佔位符,它的具體實現由子類來實現。繼承一個抽象類有兩種選擇:
在抽象類中定義部分抽象類方法或不定義抽象類方法,這樣必須將子類也聲明爲抽象類。
定義全部的抽象方法,子類可以不是抽象的。
一個類即使不含抽象方法,也可以將類聲明爲抽象類
抽象類不能被實例化,可以定義一個抽象類的對象變量,但是它只能引用非抽象子類的對象。
抽象類數組
我們先來看一個例子:
public abstract class Animal { private String name; public Animal(String name) { this.name = name; } public String getName() { return name; } public abstract String getDescription(); }
public class Tiger extends Animal { public Tiger(String name) { super(name); } @Override public String getDescription() { return "A Tiger named " + getName() + " eat meat"; } }
public class Rabbit extends Animal { public Rabbit(String name) { super(name); } @Override public String getDescription() { return "A Rabbit named " + getName() + " eat carrot"; } }
public class AnimalTest { public static void main(String[] args) { Animal[] animals = new Animal[2]; animals[0] = new Tiger("awo"); animals[1] = new Rabbit("miao"); for (Animal animal : animals) { System.out.println(animal.getDescription()); } } }
輸出結果:
A Tiger named awo eat meat
A Rabbit named miao eat carrot
由於不能構造抽象類Animal的對象,所以變量animal永遠不會引用Animal對象,而是引用諸如Tiger和Rabbit這樣的具體子類對象,而這些對象中都定義了getDescription方法,所以打印出的結果分別是兩個子類的實現,但是我們不能省略父類中的抽象方法,而僅在子類中定義,如果這樣的話,我們就不能通過變量p調用getDescription方法,編譯器只允許調用在類中聲明的方法。