什麼是抽象類?這名字聽著就挺抽象的,第一次聽到這個名字還真有可能被唬住。但是,就像老人家所說的,一切反動派都是紙老虎,一切有著裝x名字的概念也是紙老虎。好吧,我們已經從戰略上做到了藐視它,現在就要戰術上重視它,如同要解決紙老虎,就要一個牙齒一個牙齒地敲,一個爪子一個爪子地拔;解決這種抽象概念也一樣, ...
什麼是抽象類?這名字聽著就挺抽象的,第一次聽到這個名字還真有可能被唬住。但是,就像老人家所說的,一切反動派都是紙老虎,一切有著裝x名字的概念也是紙老虎。好吧,我們已經從戰略上做到了藐視它,現在就要戰術上重視它,如同要解決紙老虎,就要一個牙齒一個牙齒地敲,一個爪子一個爪子地拔;解決這種抽象概念也一樣,先要把它具體化,細分化,然後一個一個地來。
我一般遇到新的概念都會問三個問題:
1.這個東西有什麼用?用來乾什麼的?它的意義在哪裡?(顯然,如果是沒用的東西,就沒必要浪費時間了;其實,弄懂了這個問題,就掌握了60%)
2.這個概念或者技能點怎麼用?也就是它的表現形式,如關鍵字、修飾詞、語法什麼的。。。(這個占20%)
3.這個東西在用的過程中,有哪些關鍵點和細節點?(是的,也占20%)
上面三個問題搞清楚了,剩下的就是去用了。。。“無他,但手熟爾。”
一、第一個問題:抽象類有什麼用?它存在的意義是什麼?
這回答這個問題之前,先看一下動物界里的一個例子:首先,有一個父類Animal,接著有兩個子類,分別是鳥Bird和狗Dog,如下:
1 public class Animal{ 2 public void bark(){} 3 } 4 public class Bird extends Animal{ 5 public void bark(){ 6 System.out.println("唧唧~唧唧~"); 7 } 8 } 9 public class Dog extends Animal{ 10 public void bark(){ 11 System.out.println("汪汪~汪汪~"); 12 } 13 }
可以看到,父類Animal有一個叫喚的方法bark(),兩個子類都繼承了這個方法,併進行了重寫,Bird是唧唧叫,Dog是汪汪叫,現在的問題是Animal怎麼叫?它的bark()方法體里應該輸出什麼樣的叫聲,是“汪汪”還是“唧唧”?
顯然,動物是個抽象的集合名詞,我們並不知道動物Animal怎麼叫,所以,bark()方法在父類中實現不了,或者說實現了沒有任何意義,bark()方法只能在子類中根據具體情況去實現。這樣的話就可以把父類Animal中的bark()方法聲明為abstract抽象方法,此時這個類也成了abstract抽象類。
至此,也就可以回答第一個問題,抽象類用來做什麼的?抽象類自己並不能實例化,它存在的意義就是為了讓子類繼承。對於一個父類,它的某個方法在父類中實現沒有任何意義,必需在子類中根據具體情況實現,那麼這個方法可以聲明為abstract抽象方法,此時這個父類也成了abstract抽象類。(當然,你也許會想,就像上面那樣,函數的花括弧里為空不也可以?是的,語法上沒毛病,甚至用法上也沒毛病,但一般還是把它抽象成abstract方法。原因有三點:1.就像上面說的,這樣弄“實現了沒有任何意義”;2.Java裡面不鼓勵函數體的內容為空;3.用法上子類繼承父類後,子類會被強制重寫父類中的抽象方法,起到一個提醒和約束的作用。)
二、第二個問題:抽象類怎麼用?表現形式是什麼樣的?
這個問題相對簡單,就是語言設計者的一些規定,Java中規定用abstract來修飾抽象方法和抽象類。上面的Animal類寫成如下形式:
1 public abstract class Animal{ 2 public abstract void bark(); 3 }
三、第三個問題:抽象類在用的過程中有哪些關鍵點?
抽象類並不是只能包含抽象方法,他也可以包含普通的成員方法和成員變數。它和普通類的區別主要有三點:
1.抽象類中的抽象方法只能用public或protected修飾。因為,抽象方法來到世間就是為了讓子類繼承重寫的,而private屬性的方法不能被子類繼承,顯然矛盾。
2.抽象類不能創建對象,即不能實例化。因為,抽象類中包含沒有實現的抽象方法,是不完整的,所以不能用來創建對象。(有一種特殊情況,就是一個類中並沒有抽象方法,但是類class有abstract修飾,被聲明為抽象類,那麼這個類也是抽象類,也不能實例化。)
3.如果一個類繼承於一個抽象類,那麼子類必須實現父類的抽象方法。否則,子類繼承的方法還是抽象方法,子類也變成了抽象類,要用abstract修飾。(這就好比父母從小 have a dream,就是考大學,但是由於他們生活的年代、環境、個人能力等因素,總之沒實現,於是他們將這個夢想讓自己孩子繼承,並要求他們實現,至於你具體是考清華大學,還是考長江大學,那就 Let it be 了。。。當然,如果兒子不實現,就會變成抽象類,再讓孫子繼承和實現。。。)
在其他方面,抽象類和普通類並無區別。最後,再來個例子:
1 public abstract class Animal { //抽象類中可以有非抽象方法,也可以有成員變數 2 private int a = 10; 3 4 public abstract void bark(); //如果沒有此抽象方法,但是class前有absract修飾,也是抽象類,也不能實例化 5 public void say() { //普通成員方法 6 System.out.println("我是抽象類中的非抽象方法,此抽象類中的私有成員變數a= " + a); 7 } 8 9 public int getA() { 10 return a; 11 } 12 public void setA(int a) { 13 this.a = a; 14 } 15 } 16 public class Dog extends Animal{ 17 public void bark() { //子類實現Animal的抽象方法 18 System.out.println("汪汪~汪汪~"); 19 System.out.println("我是子類,不能直接調用父類的私有變數a :("); 20 System.out.println("我是子類,只有通過super.getA()調用父類的私有變數a:" + super.getA()); 21 } 22 } 23 public class Test { 24 public static void main(String[] args) { 25 Dog dog = new Dog(); 26 dog.say(); //子類繼承調用Animal的普通成員方法 27 dog.bark(); //子類調用已經實現過的方法 28 } 29 }