1. 程式人生 > >java抽象類和介面和繼承之間關係

java抽象類和介面和繼承之間關係

有時候,我們可能想要構造一個很抽象的父類物件,它可能僅僅代表一個分類或抽象概念,它的例項沒有任何意義,因此不希望它能被例項化。例如:有一個父類“ 水果(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程式碼
  1. publicinterface InterfaceA {   
  2. void methodA();   
  3. }  
 

           類ClassA實現介面InterfaceA。

Java程式碼
  1. publicclass ClassA implements InterfaceA {   
  2. publicvoid methodA() {   
  3.                System.out.println("methodA of ClassA implements InterfaceA");   
  4.          }   
  5. }  
 

如果是抽象類實現一個介面,那麼抽象類中可以不具體實現介面的方法(保持其抽象性),而由其子類去實現。
           抽象類ClassB實現介面InterfaceA,但是沒有具體實現方法methodA(),

Java程式碼
  1. publicabstractclass ClassB  {           }  
 

           子類ClassBSub實現介面InterfaceA,但是沒有具體實現方法methodA(),

Java程式碼
  1. publicclass ClassBSub {   
  2. publicvoid methodA() {   
  3.               System.out.println("methodA of ClassBSub the subclass of ClassB");   
  4.         }   
  5. }  
 

介面和抽象類顯著的共同點是介面和抽象類都可以有抽象方法。
介面和抽象類的不同點有:
           (1)抽象類可以有例項變數,而介面不能擁有例項變數,介面中的變數都是靜態(static)的常量(final)。
           (2)抽象類可以有非抽象方法,而介面只能有抽象方法。
java中,類與類之間是不能多繼承的。java之所以禁止類與類之間的多繼承是因為多繼承有很大的缺點。
多繼承雖然能使子類同時擁有多個父類的特徵,但是其缺點也是很顯著的,主要有兩方面:
(1)如果在一個子類繼承的多個父類中擁有相同名字的例項變數,子類在引用該變數時將產生歧義,無法判斷應該使用哪個父類的變數。例如:
           類ClassA:

Java程式碼
  1. publicclass ClassA {   
  2. protectedint varSame = 0;   
  3. }  
 

           類ClassB:

Java程式碼
  1. publicclass ClassB {   
  2. protectedint varSame = 1;   
  3. }  
 

           子類ClassC:(假設允許類與類之間多繼承)

Java程式碼
  1. publicclass ClassC extends ClassA, ClassB {   
  2. publicvoid printOut() {   
  3.                 System.out.println(super.varSame);   
  4.         }   
  5. publicstaticvoid main(String[] args) {   
  6.                 ClassC classC = new ClassC();   
  7.                 classC.printOut();   
  8.         }   
  9. }  
 


           上面程式的執行結果會是什麼呢?輸出0還是1?
(2)如果在一個子類繼承的多個父類中擁有相同方法,子類中有沒有覆蓋該方法,那麼呼叫該方法時將產生歧義,無法判斷應該呼叫哪個父類的方法。例如:
           類ClassA:

Java程式碼
  1. publicclass ClassA {   
  2. publicvoid printOut() {   
  3.                 System.out.println(0);   
  4.         }   
  5. }  

           類ClassB:

Java程式碼
  1. publicclass ClassB {   
  2. publicvoid printOut() {   
  3.                 System.out.println(1);   
  4.         }   
  5. }  
 

           子類ClassC:(假設允許類與類之間多繼承)

Java程式碼
  1. publicclass ClassC extends ClassA, ClassB {   
  2. publicstaticvoid main(String[] args) {   
  3.                            ClassA classA = new ClassC();   
  4.                            classA.printOut();      // -------------------------  A行
  5.                            ClassB classB = new ClassC();   
  6.                            classB.printOut();      // -------------------------  B行
  7.                            ClassC classC = new ClassC();   
  8.                            classC.printOut();       //-------------------------  C行
  9.                    }   
  10.            }  
 

           上面程式的執行結果會是什麼呢?A、B、C三行的輸出是0還是1?
正因為有以上的致命缺點,所以java中禁止一個類繼承多個父類;但是幸運的是java提供了介面,並能通過介面的功能獲得多繼承的許多優點而又摒棄了類與類多繼承的缺點。
java允許一個介面繼承多個父介面,也允許一個類實現多個介面,而這樣的多繼承有上面提到的缺點馬?
答案是沒有,這是由介面的抽象性決定的。
正如前面介紹的,在介面中不能有例項變數,只能有靜態的常量,不能有具體的方法(包含方法體),只能有抽象方法,因此也就摒棄了多繼承的缺點。
對於一個類實現多個介面的情況,因為介面只有抽象方法,具體方法只能由實現介面的類實現,在呼叫的時候始終只會呼叫實現類的方法(不存在歧義),因此不存在多繼承的第二個缺點;而又因為介面只有靜態的常量,但是由於靜態變數是在編譯期決定呼叫關係的,即使存在一定的衝突也會在編譯時提示出錯;而引用靜態變數一般直接使用類名或介面名,從而避免產生歧義,因此也不存在多繼承的第一個缺點。
對於一個介面繼承多個父介面的情況也一樣不存在這些缺點。
請看以下示例。
            介面A:

Java程式碼
  1. publicinterface InterfaceA {   
  2. int len = 1;   
  3. void output();   
  4. }  
 

            介面B:

Java程式碼
  1. publicinterface InterfaceB {   
  2. int len = 2;   
  3. void output();   
  4. }  
 

            介面Sub繼承介面A和介面B:

Java程式碼
  1. publicinterface InterfaceSub extends InterfaceA, interfaceB {            }  
 

            類Xyz實現介面Sub:

Java程式碼
  1. publicclass Xyz implements InterfaceSub {   
  2. publicvoid output() {   
  3.                 System.out.println("output in class Xyz.");   
  4.         }   
  5. publicvoid outputLen(int type) {   
  6. switch(type) {   
  7. case InterfaceA.len:   
  8.                                  System.out.println("len of InterfaceA=."+type);   
  9. break;   
  10. case InterfaceB.len:   
  11.                                  System.out.println("len of InterfaceB=."+type);   
  12. break;   
  13.                  }   
  14.         }   
  15. publicstaticvoid main(String[] args) {   
  16.                Xyz xyz= new Xyz ();   
  17.                xyz .output();   
  18.                xyz .outputLen();   
  19.        }   
 


           以上程式碼不存在什麼問題,但是如果試圖編寫以下存在衝突的程式碼,則會編譯失敗。

Java程式碼
  1. Xyz xyz = new Xyz();   
  2. int len = xyz.len;   
  3. System.out.println(len);  
 


由於引入了介面,java顯得非常靈活,也使得java中的多型性更加富有魔力。

相關推薦

Java抽象的作用使用

/* 當多個類中出現相同功能,但是功能主體不同, 這是可以進行向上抽取。這時,只抽取功能定義,而不抽取功能主體。 抽象:看不懂。 抽象類的特點:1,抽象方法一定在抽象類中。2,抽象方法和抽象類都必須被abstract關鍵字修飾。3,抽象類不可以用new建立和例項化物件

Java抽象介面的區別及default關鍵字學習總結

抽象類 可看做是不可例項化的普通類,可以擁有構造方法,可以有main方法 抽象類中的方法可以是抽象方法(抽象方法必須存在於抽象類中),也可以是普通方法、靜態方法 可以宣告變數 抽象類可以繼承其它類,也可實現介面 抽象類的派生類,必須覆蓋父類中abstract修

Java抽象介面的區別

2014/07/16 | 分類: 基礎技術 | 6 條評論 | 標籤: 抽象類, 介面 分享到: 很多常見的面試題都會出諸如抽象類和介面有什麼區別,什麼情況下會使用抽象類和什麼情況你會使用介面這樣的問題。本文我們將仔細討論這些話題。 在討論它們之間的不同點之前,

Java抽象介面的理解及default關鍵字

抽象類 可看做是不可例項化的普通類,可以擁有構造方法,可以有main方法 抽象類中的方法可以是抽象方法(抽象方法必須存在於抽象類中),也可以是普通方法、靜態方法 可以宣告變數 抽象類可以繼承其

再看Java抽象介面

寫了這麼久的介面,也很少用到抽象類。 在一些原始碼中又看到,自己平時基本不會用到抽象類,但是最近學習又不記得到底有什麼區別了,再來先看一下。 首先, java的面向物件的特徵是什麼: 面向物件程式設計有四個特徵:抽象,封裝,繼承,多型。 java墮胎的四種體現形式: 多型

java 抽象介面 note

抽象類(修飾符abstract) 兩種類:具體類和抽象類 抽象方法:設計目的就是讓子類來實現。子類繼承了抽象父類,如果沒有實現抽象父類,那麼子類還是一個抽象子類。否則子類一定要實現抽象父類裡的抽象方法,成為具體類。 如果一個方法被宣告為抽象類,則這個類必須宣告為抽象的。 在抽象類

再探Java抽象介面的設計理念差異

Java抽象類與介面都可以實現功能與實現的分離,都對多型提供了很好的支援,那麼我們什麼時候應該使用抽象類或介面呢?在以前的一篇文章初探Java抽象類與介面中談到了他們語法的區別,在部落格通過模板方法模式深入理解Java抽象類中寫到了該如何正確使用抽象類,那

java-抽象介面

1、抽象類:                   --將子類含有的相同功能抽取出來,有建構函式,但是不能建立物件(和介面一樣只有方法的宣告沒有方法的實現,建立物件沒有意義),抽象類中的方法不一定都是抽

JAVA抽象介面

Java抽象類 抽象方法:使用abstract關鍵字修飾的方法,沒有方法體,抽象方法只能使用public 或者protected修飾。 public abstract void fun(); 抽象

java 抽象介面的區別

抽象類:抽象類是用來捕捉子類的通用性的,不能被例項化,只能做為子類的超類,抽象類是被用來建立繼承層級裡子類的模板的。    首先了解一下抽象方法。抽象方法是一種特殊的方法,只宣告而沒有具體的實現,宣告格式為:abstract void fun (); 抽象方法必須由abs

JAVA抽象介面詳解 例子很好

在Java語言中, abstract class 和interface 是支援抽象類定義的兩種機制。正是由於這兩種機制的存在,才賦予了Java強大的 面向物件能力。abstract class和interface之間在對於抽象類定義的支援方面具有很大的相似性,甚至可以相互替

重新開始學Java——抽象介面、內部類

抽象類 為什麼要定義抽象方法:如果定義某個方法時不能確定該方法的具體實現細節; 比如定義 Person 類的 eat 方法時, 不

java抽象介面繼承之間關係

有時候,我們可能想要構造一個很抽象的父類物件,它可能僅僅代表一個分類或抽象概念,它的例項沒有任何意義,因此不希望它能被例項化。例如:有一個父類“ 水果(Fruit)”,它有幾個子類“蘋果(Apple)”、“橘子(Orange)”、“香蕉(Banana)”等。水果在這裡僅僅只是作為一個分類,顯然水果的例項沒有

Java物件例項的關係Java資料封裝、Java繼承多型、Java抽象介面Java靜態欄位方法、Java作用域、Java的classpathjar、Java核心

Java物件和例項的關係: 面向物件程式設計(Object-Oriented Programming),是對現實世界建立計算機模型的一種方法。 class是物件的模板,它定義瞭如何建立例項,class的名字就是資料型別。一個class裡可以有多個欄位(field),欄位用

Java抽象介面(一)

**********************第九章 抽象類和介面**************************   **************************抽象類************************** 一.why 什麼時候想到使用抽象類 需求: 矩形、三角形、

Java抽象介面(三)

***********************體會介面的好處******************************* 一.可維護、可擴充套件 面向介面程式設計 介面:父型別 面向父類程式設計   二.解耦 高內聚、低耦合 耦合: 類和類之間的關係... 只要類和類之間有四種關係

Java抽象介面(二)

***************************介面********************************* 一.why 需求一直不變的時候可以不使用介面, 需求經常發生改變推薦使用介面... 軟體產品中需求會經常改變,所以一般都要使用介面... 體現了可維護、可擴充套件的優點 二.

Java——抽象介面的區別

一.  區別 1.語法層面上的區別   1)抽象類可以提供成員方法的實現細節,而介面中只能存在public abstract 方法;   2)抽象類中的成員變數可以是各種型別的,而介面中的成員變數只能是public static final型別的;   3)介面中不能含有靜

java基礎(十二)抽象(Abstract class)介面(interface)

抽象類(Abstract class): 抽象類概述: 抽象類是對根源的抽象(即對本質的抽象與其他類的本質不同)。 抽象類表示的是這個東西是什麼。比如男人女人,,他們的抽象類就是人,所以繼承也只能繼承一個類(抽象類)(是人那就是人,不能是別的生物) 且如果有抽象的功能(吃,睡…),該

JAVA面試題:介面抽象的區別聯絡

一、介面的概念: 介面(Interface),在JAVA程式語言中是一個抽象型別,是抽象方法的集合。介面通常以interface來宣告。一個類通過繼承介面的方式,從而來繼承介面的抽象方法。 如果一個類只由抽象方法和全域性常量組成,那麼這種情況下不會將其定義為一個抽象類。只