跳转到内容

接口

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.");
}


华夏公益教科书