Java 类中实现的两个具有相同方法签名的接口

问题描述 投票:0回答:7

我有两个 Java 接口和一个实现类。

(我使用Eclipse直接运行程序,并且我没有尝试通过从命令行显式编译来检查任何编译器警告等。)

为什么他们运行没有问题?为什么 Java 允许这样做,即使它满足两个接口的“契约”,但在实现类时会产生歧义?

更新了示例。

public interface CassettePlayer {
    void play();
}

public interface DVDPlayer {
    void play();
}

public class CarPlayer implements CassettePlayer,DVDPlayer{

    @Override
    public void play() {
        System.out.println("This plays DVD, screw you Cassette !");
    }

    public static void main(String args[]) {
        CarPlayer cp = new CarPlayer();
        cp.play();

        CassettePlayer firstInterface = new CarPlayer();
        firstInterface.play();

        DVDPlayer secondInterface = new CarPlayer();
        secondInterface.play();
    }
}
java compiler-construction interface multiple-inheritance
7个回答
37
投票

“Java 语言规范”第 8.1.5 节特别允许这种情况

允许类中的单个方法声明实现多个超级接口的方法。例如,在代码中:

interface Fish { int getNumberOfScales(); } interface Piano { int getNumberOfScales(); } class Tuna implements Fish, Piano { // You can tune a piano, but can you tuna fish? int getNumberOfScales() { return 91; } }
  
  

getNumberOfScales

 中的方法 
Tuna
 的名称、签名和返回类型与接口 
Fish
 中声明的方法匹配,也与接口 
Piano
 中声明的方法匹配;它被认为同时实现。

文中接着指出,如果方法签名具有不同的返回类型,例如

double

int
,则无法在同一个类中实现这两个接口,并且会产生编译时错误。 


5
投票
对于这个问题,有必要了解接口的用途。

接口是一种“契约”,这样人们就知道在具有该接口的类中强制实现了哪些方法。

因此,如果您需要一个实现“DVDPlayer”的类(因为您需要“play()”方法),您将找到 CarPlayer。实现 CassettePlayer 的类的需求也是如此。这就是技术解释。

但是当然,在语义编码中,您应该确保 CarPlayer 的方法“play()”满足 DVDPlayer 和 CassettePlayer 的语义。我认为在实际应用中这将是一个不好的做法。

当然,在您的示例中,让两个接口声明相同的方法是一个坏主意。更实际的是,您应该使用方法“play()”创建一个接口“Player”,并拥有另外两个从 Player 继承的更具体的接口 DVDPlayer 和 CassettePlayer(具有针对 DVD 和盒式磁带的特定方法)。 另一方面,如果您不需要 DVD 或盒式磁带的特定方法,那么您不需要两个不同的接口只实现一个且相同的方法 - 只需使用一个接口 Player 就足够了。


3
投票
在这种情况下,没有问题,因为两个接口具有相同的方法签名。但这又如何呢?

interface Animal { public void eat() throws IOException; } interface Plants { public void eat() throws NullPointerException; }

编译器选择哪一个?为什么下面的代码会出错?

public class Test implements Animal, Plants { public void eat() throws IOException { } }

编译器说:异常 IOException 与 Plants.eat() 中的 throws 子句不兼容


1
投票
不存在冲突,因为它们都指定相同的契约,实现类仅提供通过任一接口引用时调用的一个方法。


1
投票
为什么不呢?该类满足两个接口定义的契约。


1
投票
该类实现了两个接口 - 所以没问题。 当然,在可能导致意外行为的更复杂的场景中应该避免这种事情。


1
投票
以下页面包含一个类的示例 实现了两个具有

的接口

    相同的变量名
  1. 每个界面的方法相同。

https://www.javadeploy.com/java-language/module2/inside-java-interfaces.jsp

© www.soinside.com 2019 - 2024. All rights reserved.