跳轉到內容

介面

100% developed
來自華夏公益教科書

導航類和物件主題:v  d  e )

介面是類的抽象,沒有實現細節。例如,java.lang.Comparable 是 Java 中的標準介面。你無法例項化介面。介面不是類,但它以相同的方式編寫。第一個區別是,你不用 class 關鍵字,而是用 interface 關鍵字來定義它。然後,你不能在這裡定義欄位和方法

  • 欄位始終是常量:它始終是公共的、靜態的和最終的,即使你沒有提到它。
  • 方法必須是公共的和抽象的,但不需要寫 publicabstract 關鍵字。
  • 建構函式是被禁止的。

介面代表一個契約

Computer code 程式碼清單 4.14:SimpleInterface.java
public interface SimpleInterface {
    public static final int CONSTANT1 = 1;
    int method1(String parameter);
}

你可以看到 method1() 方法是抽象的(未實現)。要使用介面,你必須定義一個實現它的類,使用 implements 關鍵字

Computer code 程式碼清單 4.15:ClassWithInterface.java
public class ClassWithInterface implements SimpleInterface {
    public int method1(String parameter) {
        return 0;
    }
}

一個類可以實現多個介面,用逗號分隔。Java 介面的行為與 Objective-C 協議的概念非常相似。建議將介面命名為 <動詞>able,表示此介面將在類上啟用的操作型別。但是,不建議在介面名稱前面加上 I,如 C++ 中那樣。這沒有用。你的 IDE 會為你提供幫助。

如果你有來自不同類且沒有共同超類的物件,你無法在這些類中呼叫相同的方法,即使這兩個類實現了具有相同簽名的方法。

Computer code 程式碼清單 4.16:OneClass.java
public class OneClass {
    public int method1(String parameter) {
        return 1;
    }
}
Computer code 程式碼清單 4.17:AnotherClass.java
public class AnotherClass {
    public int method1(String parameter) {
        return 2;
    }
}
Warning 程式碼部分 4.16:無法呼叫。
public static void main(String[] args) {
    doAction(new OneClass());
    doAction(new AnotherClass());
}

public void doAction(Object anObject) {
    anObject.method1("Hello!");
}

解決方法是編寫一個定義應該在兩個類中實現的方法的介面,如 程式碼清單 4.14 中的 SimpleInterface,然後這兩個類都可以實現介面,如 程式碼清單 4.15 中那樣。

Example 程式碼部分 4.17:介面使用。
public static void main(String[] args) {
    doAction(new ClassWithInterface());
    doAction(new AnotherClassWithInterface());
}

public void doAction(SimpleInterface anObject) {
    anObject.method1("Hello!");
}

你也可以使用一個共同的超類來實現這一點,但一個類只能從一個超類繼承,而它可以實現多個介面。

Java 不支援完全正交多重繼承(即 Java 不允許你從兩個類建立子類)。C++ 中的多重繼承有複雜的規則來消除從多個超類繼承的欄位和方法以及多次繼承的型別的歧義。透過將介面與實現分離,介面在複雜性和歧義性較小的情況下提供了多重繼承的大部分優勢。沒有多重繼承的代價是一些程式碼冗餘;由於介面只定義類的簽名,而不能包含任何實現,所以每個繼承介面的類都必須提供定義方法的實現,不像純粹的多重繼承那樣,實現也是繼承的。這樣做的主要好處是,所有 Java 物件都可以有一個共同的祖先(一個名為 Object 的類)。

在覆蓋介面中定義的方法時,需要遵循一些規則

  • 不應該在實現方法上宣告受檢異常,除了介面方法宣告的異常或介面方法宣告的異常的子類。
  • 在實現方法時,應該保持介面方法的簽名和相同的返回型別或子型別。
  • 實現介面的類需要定義介面的所有方法,除非該類是抽象類。

擴充套件介面

[編輯 | 編輯原始碼]
在 BlueJ 上執行此示例。

介面可以擴充套件多個介面,類似於類可以擴充套件另一個類的方式,使用 extends 關鍵字

Computer code 程式碼清單 4.18:InterfaceA.java
public interface InterfaceA {
  public void methodA();
}
Computer code 程式碼清單 4.19:InterfaceB.java
public interface InterfaceB {
  public void methodB();
}
Computer code 程式碼清單 4.20:InterfaceAB.java
public interface InterfaceAB extends InterfaceA, InterfaceB {
  public void otherMethod();
}

這樣,實現InterfaceAB介面的類必須實現methodA()methodB()otherMethod()方法。

Computer code 程式碼清單 4.21:ClassAB.java
public class ClassAB implements InterfaceAB {
  public void methodA() {
    System.out.println("A");
  }

  public void methodB() {
    System.out.println("B");
  }

  public void otherMethod() {
    System.out.println("foo");
  }

  public static void main(String[] args) {
    ClassAB classAb = new ClassAB();
    classAb.methodA();
    classAb.methodB();
    classAb.otherMethod();
  }
}

這樣做,ClassAB物件可以被強制轉換為InterfaceAInterfaceBInterfaceAB

測試你的知識

問題 4.2:考慮以下介面。

Computer code 問題 4.2:Walkable.java
public interface Walkable {
    void walk();
}
Computer code 問題 4.2:Jumpable.java
public interface Jumpable {
    void jump();
}
Computer code 問題 4.2:Swimable.java
public interface Swimable {
    void swim();
}
Computer code 問題 4.2:Movable.java
public interface Movable extends Walkable, Jumpable {
}

列出實現Movable類的所有方法。

答案
  • walk()
  • jump()
Computer code 答案 4.2:Person.java
public class Person implements Movable {
    public void walk() {
        System.out.println("Do something.");
    }

    public void jump() {
        System.out.println("Do something.");
    }
}

問題 4.3:考慮以下類和以下程式碼。

Computer code 問題 4.3:ConsoleLogger.java
import java.util.Date;

public class ConsoleLogger {
    public void printLog(String log) {
        System.out.println(new Date() + ": " + log);
    }
}
Computer code 問題 4.3:FileLogger.java
import java.io.File;
import java.io.FileOutputStream;

public class FileLogger {
  public void printLog(String log) {
    try {
      File file = new File("log.txt");
      FileOutputStream stream = new FileOutputStream(file);
      byte[] logInBytes = (new Date() + ": " + log).getBytes();

      stream.write(logInBytes);

      stream.flush();
      stream.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
Example 問題 4.3:通用程式碼。
Object[] loggerArray = new Object[2];
loggerArray[0] = new ConsoleLogger();
loggerArray[1] = new FileLogger();

for (Object logger : loggerArray) {
    // logger.printLog("Check point.");
}

更改程式碼實現,以便能夠取消註釋註釋的行而不出現編譯錯誤。

答案

你必須建立一個介面,定義方法printLog(String),並使ConsoleLoggerFileLogger實現它。

Computer code 答案 4.3:Logger.java
public interface Logger {
    void printLog(String log);
}
Computer code 答案 4.3:ConsoleLogger.java
import java.util.Date;

public class ConsoleLogger implements Logger {
    public void printLog(String log) {
        System.out.println(new Date() + ": " + log);
    }
}
Computer code 答案 4.3:FileLogger.java
import java.io.File;
import java.io.FileOutputStream;

public class FileLogger implements Logger {
  public void printLog(String log) {
    try {
      File file = new File("log.txt");
      FileOutputStream stream = new FileOutputStream(file);
      byte[] logInBytes = (new Date() + ": " + log).getBytes();

      stream.write(logInBytes);

      stream.flush();
      stream.close();
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

現在你的程式碼必須將物件強制轉換為Logger型別,然後才能取消註釋程式碼。

Example 答案 4.3:通用程式碼。
Logger[] loggerArray = new Logger[2];
loggerArray[0] = new ConsoleLogger();
loggerArray[1] = new FileLogger();

for (Logger logger : loggerArray) {
    logger.printLog("Check point.");
}


華夏公益教科書