2

在 Java 中,当您向接口添加新方法时,您会破坏所有客户端。当您有一个抽象类时,您可以添加一个新方法并在其中提供一个默认实现。所有客户将继续工作。

我想知道为什么界面是这样设计的?

所有旧方法仍然存在,因此似乎没有向后兼容性问题。(当然需要有某些例外,但我认为能够在不破坏客户端的情况下向 java 接口添加新方法可能是一个非常好的主意......)

我会很感激你的意见。

4

4 回答 4

3

我可以看到一些可能的中断

  • 您假设客户端将使用新的重载方法,但他们没有这样做,因为代码尚未重新编译。
  • 您添加一个客户端已经拥有的方法,该方法执行不同的操作。
  • 您添加一个方法,这意味着它们的子类在重新编译时会中断。恕我直言,这是可取的。
  • 您更改返回类型、方法名称或参数类型,这将在运行时导致错误。
  • 您交换相同类型的参数。这可能是最糟糕和最微妙的错误。;)

恕我直言,这是更可能导致您悲伤的微妙问题。但是,我不会假设简单地添加一个方法会破坏代码,我不会假设如果客户端的代码没有出现运行时错误,则意味着他们使用的是最新版本的任何东西。;)


如果我编译这段代码

public interface MyInterface {
    void method1();

    // void method2();
}

public class Main implements MyInterface {
    @Override
    public void method1() {
        System.out.println("method1 called");
    }

    public static void main(String... args) {
        new Main().method1();
    }
}

它打印

method1 called

然后我取消注释 method2() 并重新编译接口。这意味着接口有一个Main没有实现的方法。然而,当我在不重新编译的情况下运行它时,Main我得到了

method1 called

如果我有

public class Main implements MyInterface {    
    public void method1() {
        System.out.println("method1 called");
    }

    public void method2() {
        System.out.println("method2 called");
    }

    public static void main(String... args) {
        new Main().method1();
    }
}

我在// method2()注释掉的情况下运行,我没有问题。

于 2012-09-24T08:51:43.153 回答
1

接口就像一个类的模板。当您有一个对象的类实现了某个接口并且您对该接口进行强制转换时,您只能通过该接口访问该对象(及其方法)。因此,您的客户将始终看到接口提供的所有方法,而不仅仅是那些实际上由类实现的方法。

您的建议会让您想知道您在任何时候处理的对象是否确实具有他们试图调用的方法的实现。

当然,在您的场景中,遗留客户端不会发生这种情况,直到您想在一段时间内更新它们并且您依赖于您的对象对您的 IDE 预览的所有方法都有实现。:)

抽象类的事实是(正如您所提到的)您提供了默认实现,因此可以在客户端依赖您的对象实现方法。

希望这有助于解决问题。

问候

于 2012-09-24T08:48:50.670 回答
0

接口表示从该接口对其用户可用的一组所有方法,而不是可以添加其他方法的一些方法。这是一份不少也不多的契约。

这种设计最好的一点是没有歧义。Java 是一种静态类型语言,需要从接口声明中完全了解所有可用方法。在 JVM 内部,只有一个接口类表示,它需要包含完整的可用抽象方法集。

当您有一个具有一些已实现方法的抽象类时,它的语义是一个无法实例化但其唯一目的是扩展并实现其抽象方法的类。抽象类强制执行 IS-A 关系,而接口强制执行 BEHAVES-AS

于 2012-09-24T08:57:12.480 回答
0

接口的作用不仅仅是方法的声明。它们构成了基于合同/首次开发的基础。这些合约 API 定义了什么是输入,什么是输出。和任何合同一样,它们只有在满足所有条件时才有效。这就是类必须实现已实现接口的所有api的原因。

有一些设计模式定义了处理版本和新开发的方式。在实例化这些接口的实现时应该使用的工厂/抽象工厂模式(以便它们可以在内部验证要使用的正确版本是实现)。

您所要求的灵活性可以通过适当的设计来实现,而不是期望通过编程语言来实现。对于将新版本实现插入旧接口的编程工具是编程错误。但它不同于向后兼容中断。更新版本的组件的可用性并不一定意味着会有向后兼容性中断。成熟的产品或组件总是支持旧版本,只要它们不会成为真正的维护难题。因此,在大多数情况下,除非有一些您想使用的新功能,否则用户不必担心更新版本的可用性。

于 2012-09-24T09:04:52.327 回答