淺談Java接口(Interface)


淺談Java接口

先不談接口,不妨設想一個問題?

如果你寫了個Animal類,有許多類繼承了他,包括Hippo(河馬), Dog, Wolf, Cat, Tiger這幾個類。你把這幾個類拿給別人用,但是別人想給動物加上寵物功能,要怎么辦呢?

根據以往的知識,我們可以:

  1. 把Pet方法加入Animal類

    • 這樣所有的派生類都有Pet方法,以后新繼承Animal的動物也有這個方法。

    • 這個方案很簡單,但是這個方案也很操蛋。為什么?

      • 有人會養河馬嗎?有人會養狼養獅子嗎?不太行。
      • 如果都是Pet方法,狗需要遛,貓恐怕不太需要遛呀。不太行
    • 所以,這個方案,不太行。

  2. 還是和第一種方法一樣,但是把Pet方法設成抽象方法

    • 方案很好,每個派生類可以覆蓋自己方法。不是Pet的就不做動作,不同的Pet有不同的行為。
    • 可是,這個方案很友好嗎?
      • 所有的派生類都需要覆蓋這個方法,非常浪費時間,怕不是要累死程序員。
      • 這種實現很不理想,很不面向對象,不是寵物的派生類也需要覆蓋這樣的方法。
      • 使得基類Animal變得非常局限,如果加入復雜的程序會變得難以利用。
  3. 把方法具體加到需要的類里

    • 具體類具體實現。
    • 繼承和多態完全失效。同樣會累死程序員。
    • 無法確保寫在派生類里的方法能夠和基類產生合約,容易破壞面向對象的基本規則。
  4. 多繼承

    • 這是最好的思路,一個類有兩個基類。例如Cat既繼承Animal,又繼承Pet。而Tiger則只需要繼承Animal。
    • 可是,出大問題!
      • 一是多繼承本身的問題。假設我有一個基類1Cat,一個基類2Dog。兩個基類里都有一個方法叫做play。那么一個派生類繼承Cat同時繼承Dog,那么派生類調用play方法時,就不知道是Cat的play還是Dog的play了。這就叫多繼承的沖突。又稱致命方塊問題
      • 更何況,Java是不允許“實現多繼承”,簡稱不允許“多繼承”。 (畢竟往高端了說,Java的設計者是想設計一門不容易出錯的工業型語言。往低端了說,Java設計者認為程序員都是弱弟弟)

難道這個問題就沒有解決方案了嗎?下面就歡迎我們今天的主角——

接口

首先,什么是接口?

接口(英文:Interface),在Java編程語言中是一個抽象類型,是抽象方法的集合,接口通常以interface來聲明。一個類通過繼承接口的方式,從而來繼承接口的抽象方法。

回到剛剛第四個方法,如果想用多繼承的思路但是又不產生沖突,那要怎么辦呢?那就用接口。

接口解決沖突的方法很簡單,把所有方法都設為抽象的,如此一來,派生類要調用這些方法,就必須重新實現一遍,這樣JVM就不會搞混了!

所有,接口就類似於一個100%的純抽象類,可他又不是類

接口並不是類,編寫接口的方式和類很相似,但是它們屬於不同的概念。類描述對象的屬性和方法。接口則包含類要實現的方法。

除非實現接口的類是抽象類,否則該類要定義接口中的所有方法。

接口無法被實例化,但是可以被實現。一個實現接口的類,必須實現接口內所描述的所有方法,否則就必須聲明為抽象類。另外,在 Java 中,接口類型可用來聲明一個變量,他們可以成為一個空指針,或是被綁定在一個以此接口實現的對象。

如何編寫接口

public interface Pet{
    // 關鍵詞 interface
    public abstract void play(); // public abstract可以省略,抽象方法沒有內容
}

接口的實現

class Dog extends Animal implements Pet{
    // 關鍵詞 implements
    // 接口的實現必須在某個類的繼承之下
    public void play(){
        // 必須實現這個方法
    }
}

接口的特性

  • 接口中每一個方法也是隱式抽象的,接口中的方法會被隱式的指定為 public abstract(只能是 public abstract,其他修飾符都會報錯)。

    public interface Pet{
        public abstract void play(); // 抽象方法,分號結尾
    }
    

    其實不像上面那么寫也可以

    public interface Pet{
        void play(); // 隱含了public abstract
    }
    
  • 接口中可以含有變量,但是接口中的變量會被隱式的指定為 public static final 變量(並且只能是 public,用 private 修飾會報編譯錯誤)。

  • 接口中的方法是不能在接口中實現的,只能由實現接口的類來實現接口中的方法。

我們為什么需要接口?

  • 使用接口可以繼承超過一個以上的來源。類可以繼承一個基類同類實現其他許多接口。同時其他的類也可以實現同一個接口,這樣可以為不同的需求組合出不同的繼承層次。
  • 接口使得代碼嚴謹。不論你來自哪里,只要你實現了這個接口,就一定會實現接口中的方法!
  • 接口更高層,同樣的方法在不同層次的類有不同的實現細節,這是很合理的。

接口與抽象類的區別

  1. 抽象類中的方法可以有方法體,就是能實現方法的具體功能,但是接口中的方法不行。
  2. 抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是 public static final 類型的。
  3. 接口中不能含有靜態代碼塊以及靜態方法(用 static 修飾的方法),而抽象類是可以有靜態代碼塊和靜態方法。
  4. 一個類只能繼承一個抽象類,而一個類卻可以實現多個接口。

接口的繼承

  • 接口和類一樣,都可以繼承。也使用extends關鍵詞,子接口繼承父接口的方法,但是可以改變傳入參數。

    public interface Pet{
        void play();
    }
    
    
    interface wild_Pet extends Pet{
        void play(String location);
    }
    
  • 雖然類不可以多繼承,但是接口可以呀! 在接口的多繼承中extends關鍵字只需要使用一次,在其后跟着繼承接口。

    interface wild_Pet extends Pet, Sweeties{}
    

    Pet和Sweeties可能定義或繼承了相同的方法,但是沒有關系,他們都是抽象的!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM