一。抽象類
有時候,我們可能想要構造一個很抽象的父類對象,它可能僅僅代表一個分類或抽象概念,它的實例沒有任何意義,因此不希望它能被實例化。例如:有一個父類“ 水果(Fruit)”,它有幾個子類“蘋果(Apple)”、“橘子(Orange)”、“香蕉(Banana)”等。水果在這里僅僅只是作為一個分類, 顯然水果的實例沒有什么意義(就好像一個人如果告訴你他買了一些水果但是卻不告訴你是蘋果還是橘子,你很難想象他到底買的是什么。)。而水果類又要能被子 類化,這就要求我們使用抽象類(abstract class)來解決這個問題。 在java中,通過在class關鍵字前增加abstract修飾符,就可以將一個類定義成抽象類。抽象類不能被實例化。例如: 定義抽象類水果(Fruit) public abstract class Fruit { …… } 如果我們試圖用以下語句來獲得一個實例,將無法編譯成功。 Fruit fruit = new Fruit(); 而我們仍然可以構造水果類的子類,如: 子類“蘋果(Apple)” public class Apple extends Fruit { …… } 子類“橘子(Orange)” public class Orange extends Fruit { …… } 這樣就達到我們的目的了。 抽象類除了能象普通類一樣可以擁有一般的屬性和方法,也可以擁有抽象方法(abstract method)。例如: 抽象類“形狀(Shape)”擁有抽象方法draw()。 public abstract class Shape { …… public abstract void draw(); …… } 抽象方法與抽象的行為相對應,通常是這個行為對父對象沒有意義,而子對象有具體動作。例如方法draw()對于類Shape沒有意義,而類 Shape的子類矩形(Rectangle)的方法draw()可以有實際的動作(根據矩形的四個頂點畫出矩形的四個邊),子類圓(Circle)的方法 draw()也可以有實際的動作(根據圓心和半徑畫出圓周)。 抽象類可以有抽象方法也可以沒有抽象方法;但是如果一個類有抽象方法,那這個類只能定義為抽象類。 如果按照以下代碼類“形狀(Shape)”仍然擁有抽象方法draw(),但沒有定義為抽象類,將會編譯失敗。 public class Shape { …… public abstract void draw(); …… } 抽象方法還有一個特點是,它強迫子類要么仍然保持抽象性(即不具體實現該方法并仍然定義為抽象類),要么具體表現出這個方法的行為(實現具體的動作或者通過拋出UnsupportedOperationException異常來表明不支持該行為)。這樣也可以強化多態性。
二 接口
下面談談接口(interface)。java語言使用關鍵字interface定義一個接口。接口也是抽象對象,它甚至比抽象類更抽象。接口中的方法都是抽象方法。 一個接口可以繼承其他接口;一個類通過關鍵字implements聲明要實現一個接口,并具體實現接口的方法。 例如:有一個接口InterfaceA, Java代碼 public interface InterfaceA { void methodA(); } 類ClassA實現接口InterfaceA。 Java代碼 public class ClassA implements InterfaceA { public void methodA() { System.out.PRintln( "methodA of ClassA implements InterfaceA" ); } } 如果是抽象類實現一個接口,那么抽象類中可以不具體實現接口的方法(保持其抽象性),而由其子類去實現。 抽象類ClassB實現接口InterfaceA,但是沒有具體實現方法methodA(), Java代碼 public abstract class ClassBS implements InterfaceA{ } 子類ClassBSub實現接口InterfaceA,但是沒有具體實現方法methodA(), Java代碼 public class ClassBSub implements InterfaceA{ public void methodA() { System.out.println( "methodA of ClassBSub the subclass of ClassB" ); } }
接口和抽象類顯著的共同點是接口和抽象類都可以有抽象方法。 接口和抽象類的不同點有: (1)抽象類可以有實例變量,而接口不能擁有實例變量,接口中的變量都是靜態(static)的常量(final)。 (2)抽象類可以有非抽象方法,而接口只能有抽象方法。
java允許一個接口繼承多個父接口,也允許一個類實現多個接口,而這樣的多繼承有上面提到的缺點馬? 答案是沒有,這是由接口的抽象性決定的。 正如前面介紹的,在接口中不能有實例變量,只能有靜態的常量,不能有具體的方法(包含方法體),只能有抽象方法,因此也就摒棄了多繼承的缺點。 對于一個類實現多個接口的情況,因為接口只有抽象方法,具體方法只能由實現接口的類實現,在調用的時候始終只會調用實現類的方法(不存在歧義), 因此不存在多繼承的第二個缺點;而又因為接口只有靜態的常量,但是由于靜態變量是在編譯期決定調用關系的,即使存在一定的沖突也會在編譯時提示出錯;而引 用靜態變量一般直接使用類名或接口名,從而避免產生歧義,因此也不存在多繼承的第一個缺點。 對于一個接口繼承多個父接口的情況也一樣不存在這些缺點。 請看以下示例。 接口A: Java代碼 public interface InterfaceA { int len = 1 ; void output(); } 接口B: Java代碼 public interface InterfaceB { int len = 2 ; void output(); } 接口InterfaceSub繼承接口A和接口B: Java代碼 public interface InterfaceSub extends InterfaceA, interfaceB { } 類Xyz實現接口InterfaceSub: Java代碼 public class Xyz implements InterfaceSub { public void output() { System.out.println( "output in class Xyz." ); } public void outputLen( int type) { switch (type) { case InterfaceA.len: System.out.println( "len of InterfaceA=." +type); break ; case InterfaceB.len: System.out.println( "len of InterfaceB=." +type); break ; } } public static void main(String[] args) { Xyz xyz= new Xyz (); xyz .output(); xyz .outputLen(); } 以上代碼不存在什么問題,但是如果試圖編寫以下存在沖突的代碼,則會編譯失敗。 Java代碼 Xyz xyz = new Xyz(); int len = xyz.len; System.out.println(len);
新聞熱點
疑難解答