大數據課程體系-學習筆記-第一階段-Java Base

接口和抽象類

簡要說明

當初在學習Java的時候,對於接口和抽象類的概念不是十分清晰,感覺二者幾乎一樣,沒有什麼本質的區別,在這個假期第二次讀了《Android源碼設計模式解析與實戰》後,深刻認識到了抽象類和接口的重要性,在這裏和大家一起梳理一下二者。

參考資料

  1. http://www.cnblogs.com/dolphin0520/p/3811437.html
  2. http://blog.csdn.net/chenssy/article/details/12858267
  3. http://www.importnew.com/7302.html

例子對比

  1. 請大家仔細對比,下面看一個網上流傳最廣泛的例子:門和警報的例子:門都有open( )和close( )兩個動作,此時我們可以定義通過抽象類和接口來定義這個抽象概念:
  2. 抽象類
abstract class Door {
    String door;    //可以有默認變量
    private String Name; //可以有私有變量
    protected String name; //可以有保護變量
    public String brand;//可以有公有變量
    //可以有構造函數
    public Component(String name){
        this.name = name;
    }
    //可以有抽象方法
    public abstract void open();
    public abstract void close();
    //可以有非抽象方法
    public void doSomething(){
         System.out.println("Open");
    }
}
  1. 接口
interface Door {
    String door; //只有默認變量,爲 public static final 修飾
    public abstract void open();  //只有抽象方法
    public abstract void close();
}

抽象類

  1. 抽象方法:一種特殊的方法:它只有聲明,而沒有具體的實現
  2. 抽象方法必須用abstract關鍵字進行修飾。
  3. 抽象類必須在類前用abstract關鍵字修飾。
  4. 如果一個類含有抽象方法,則稱這個類爲抽象類,
  5. 因爲抽象類中含有無具體實現的方法,所以不能用抽象類創建對象。
  6. 在其他方面,抽象類和普通的類並沒有區別。

接口

  1. 要讓一個類遵循某組特地的接口需要使用implements關鍵字,具體格式如下:
  2. class ClassName implements Interface1,Interface2,[....]{
    }

  3. 一個類遵循多個特定的接口。

  4. 如果一個非抽象類遵循了某個接口,就必須實現該接口中的所有方法。
  5. 如果一個抽象類遵循某個接口,可以不實現該接口中的抽象方法。

區別與聯繫

語法區別

  1. 抽象類可以提供成員方法的實現細節,而接口中只能存在public abstract 方法;

  2. 抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是public static final類型的;

  3. 接口中不能含有靜態代碼塊以及靜態方法,而抽象類可以有靜態代碼塊和靜態方法;

  4. 一個類只能繼承一個抽象類,而一個類卻可以實現多個接口

設計區別

  1. 抽象類是對一種事物的抽象,即對類抽象,而接口是對行爲的抽象。
  2. 回到上面門的例子上,將其簡化
  3. 門和警報的例子:門都有open( )和close( )兩個動作,此時我們可以定義通過抽象類和接口來定義這個抽象概念:
  4. 設計成抽像類:

    abstract class Door {
    public abstract void open();
    public abstract void close();
    }

  5. 或者設計成接口:

    interface Door {
    public abstract void open();
    public abstract void close();
    }

  6. 但是現在如果我們需要門具有報警alarm( )的功能,那麼該如何實現?下面提供兩種思路:

      1)將這三個功能都放在抽象類裏面,但是這樣一來所有繼承於這個抽象類的子類都具備了報警功能,但是有的門並不一定具備報警功能;

      2)將這三個功能都放在接口裏面,需要用到報警功能的類就需要實現這個接口中的open( )和close( ),也許這個類根本就不具備open( )和close( )這兩個功能,比如火災報警器。

      從這裏可以看出, Door的open() 、close()和alarm()根本就屬於兩個不同範疇內的行爲,open()和close()屬於門本身固有的行爲特性,而alarm()屬於延伸的附加行爲。因此最好的解決辦法是單獨將報警設計爲一個接口,包含alarm()行爲,Door設計爲單獨的一個抽象類,包含open和close兩種行爲。再設計一個報警門繼承Door類和實現Alarm接口。

interface Alram {
    void alarm();
}

abstract class Door {
    void open();
    void close();
}

class AlarmDoor extends Door implements Alarm {
    void oepn() {
      //....
    }
    void close() {
      //....
    }
    void alarm() {
      //....
    }
}

JDK8中的新特性-default方法(defender方法)(轉載)

原文鏈接
我們都知道在Java語言的接口中只能定義方法名,而不能包含方法的具體實現代碼。接口中定義的方法必須在接口的非抽象子類中實現。下面就是關於接口的一個例子:

public interface SimpleInterface {
  public void doSomeWork();
}

class SimpleInterfaceImpl implements SimpleInterface{
  @Override
  public void doSomeWork() {
    System.out.println("Do Some Work implementation in the class");
  }

  public static void main(String[] args) {
    SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
    simpObj.doSomeWork();
  }
}

那麼,如果我們在SimpleInterface裏面添加一個新方法,會怎樣呢?

public interface SimpleInterface {
  public void doSomeWork();
  public void doSomeOtherWork();
}
  1. 如果我們嘗試編譯上面的這段代碼,會得到如下結果:
$javac .\SimpleInterface.java
.\SimpleInterface.java:18: error: SimpleInterfaceImpl is not abstract and does not 
override abstract method doSomeOtherWork() in SimpleInterface
class SimpleInterfaceImpl implements SimpleInterface{
^
1 error

因爲接口有這個語法限制,所以要直接改變/擴展接口內的方法變得非常困難。我們在嘗試強化Java 8 Collections API,讓其支持lambda表達式的時候,就面臨了這樣的挑戰。爲了克服這個困難,Java 8中引入了一個新的概念,叫做default方法,也可以稱爲Defender方法,或者虛擬擴展方法(Virtual extension methods)。Default方法是指,在接口內部包含了一些默認的方法實現(也就是接口中可以包含方法體,這打破了Java之前版本對接口的語法限制),從而使得接口在進行擴展的時候,不會破壞與接口相關的實現類代碼。接下來,讓我們看一個例子:

public interface SimpleInterface {
  public void doSomeWork();

  //A default method in the interface created using "default" keyword
  //使用default關鍵字創在interface中直接創建一個default方法,該方法包含了具體的實現代碼
  default public void doSomeOtherWork(){
    System.out.println("DoSomeOtherWork implementation in the interface");
  }
}

class SimpleInterfaceImpl implements SimpleInterface{
  @Override
  public void doSomeWork() {
    System.out.println("Do Some Work implementation in the class");
  }
  /*
 1. Not required to override to provide an implementation 
 2. for doSomeOtherWork.
 3. 在SimpleInterfaceImpl裏,不需要再去實現接口中定義的doSomeOtherWork方法
   */

  public static void main(String[] args) {
    SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
    simpObj.doSomeWork();
    simpObj.doSomeOtherWork();
  }
}

該程序的輸出是:

Do Some Work implementation in the class
DoSomeOtherWork implementation in the interface

如果一個類實現了兩個接口(可以看做是“多繼承”),這兩個接口又同時都包含了一個名字相同的default方法,那麼會發生什麼情況? 在這樣的情況下,編譯器會報錯。用例子來解釋一下:

public interface InterfaceWithDefaultMethod {
  public void someMethod();
  default public void someOtherMethod(){
    System.out.println("Default method implementation in the interface");
  }
}
public interface InterfaceWithAnotherDefMethod {
  default public void someOtherMethod(){
    System.out.println("Default method implementation in the interface");
  }
}

然後我們定義一個類,同時實現以上兩個接口:

public class DefaultMethodSample implements
  InterfaceWithDefaultMethod, InterfaceWithAnotherDefMethod{

  @Override
  public void someMethod(){
    System.out.println("Some method implementation in the class");
  }
  public static void main(String[] args) {
    DefaultMethodSample def1 = new DefaultMethodSample();
    def1.someMethod();
    def1.someOtherMethod();
  }  
}

如果編譯以上的代碼,會得到一個編譯器錯誤,因爲編譯器不知道應該在兩個同名的default方法中選擇哪一個,因此產生了二義性。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章