问题 一个类必须遵守所记录的接口的合同,才能说是实现该接口


我知道实现接口意味着什么(技术上),但我不确定我是否理解“合同”包含的内容:

让我们说我上课了 MyList 实现 java.util.List (也就是说,我使用编译的代码实现所有方法),是 MyList 一个 List 然后?或者我是否需要阅读我覆盖的方法的所有注释,并确保我的实现满足这些行为的“期望”?


11621
2018-06-18 14:38


起源

MyList是一个列表吗?是 - Enzokie
@Enzokie所以我要实施 add 什么也不做 get 要始终返回null,您仍然会将其称为List吗? - Raphael Roth
只要您实现List,它仍然称为列表。在一天结束时,您决定是否在某些已实现的方法上放置某些内容或抛出一些不支持的异常,但事实仍然是它仍被称为列表。 - Enzokie


答案:


从技术上讲,是的, MyList 是一个 List 如果它实现了所有的方法 List 接口。但编译器不是魔术师。它无法检查您的方法是否应该执行它们应该执行的操作。当然,每种方法都应该按照文档所说的做。

如果我收到了 List, 和这个 List 是一个实例 MyList,我打电话 list.add("foo"),我希望在列表的末尾添加“foo”。不被删除,或添加两次,或其他任何行为。所以,当然,如果你的类实现了 List,其方法应符合其API文档中定义的合同。

想象一下你卖车。我去你的商店买车。对我来说,它是一辆汽车,因为它看起来像所有其他汽车:它有车轮,踏板,窗户等。但是,如果我按下加速器,它会刹车,当我打开灯,它鸣喇叭,当我打开窗户,它加速并杀死一个可怜的孩子在路上,我将不会很高兴,你会遇到麻烦,因为你卖给我的车行为不正常。


12
2018-06-18 14:44



哈哈很棒的例子+1 - rpax
那么就没有正式的方法来判断我的实现是“正确”还是“错误”,听起来很模糊,而且都是关于(非正式)期望的。如果接口/抽象类带有一个单元测试,它决定实现类是否满足所有期望,那将是很好的。目前,API文档可能会发生变化,使我的实现突然失效(我不知道)。 - Raphael Roth
JDK不提供这样的单元测试。由你来实现它。但合同永远不会改变:那将破坏所有现有的Java代码。实施标准集合根本不是一项常见任务。 JDK和Guava等常用库为99.999%的用例提供了所需的一切。在我20年的Java编程中,我无法重新实现一次标准集合。 - JB Nizet
@RaphaelRoth这样做的一个简单方法就是Python:您可以在文档中包含用法示例,您可以将它们作为测试运行。然而,这实际上非常脆弱。这样做的“真正方式”将转向正式方法并提供 样张 编译器,该方法满足接口所需的属性。存在执行此操作的语言。 - Bakuriu


在Java中,类和接口之间的区别在于类具有方法实现。界面没有。所以一个接口可能有一个add()方法,但是不会说任何关于add的工作方式。类需要定义添加的工作方式。

您放置时实现接口 implements InterfaceName 在你的班级定义中。然后,您必须定义界面的所有方法,否则您的应用程序将无法编译。那么是的,说MyClass是一个MyInterface是正确的 - 你甚至可以去MyInterface interface = new MyClass();

是的,您应该阅读所有注释并确保您的类以预期的方式实现接口。否则你最终会得到一些编译但可能无法正常工作的东西。


2
2018-06-18 14:45



不,java.util.List不是一个类 - Raphael Roth
修复了你甚至发布之前:) - Gabe Sechan
呃..java 8+允许在接口上实现。有限,但有可能。 - rpax


接口是合同的必要最低要求:正如你所说,如果它没有编译,你就无法履行合同!但是语言可能无法定义和限制界面的全部要求,因此您也应该注意这些期望。

一个简单的例子是 ICloneable 接口。如果您所做的只是实施

public MyObject clone() {
    return (MyObject)super.clone();
} // clone()

那么你已经完成了语言合同,也许你的班级合同也是如此。但是如果你的班级包含一个 List,那么你会惊讶你的用户:“那没有 clone() 对!”

合同还包括用户期望。打破他们,虽然语言律师可能会说你的班级是-a List,其他人不同意..


1
2018-06-18 14:49



是什么 ICloneable你正在谈论的接口? java.lang.Cloneable 是一个标记界面,甚至不会强制您覆盖 clone()。但你是对的,标记接口(序列化 将是另一个流行的例子)只作为履行合同的一种承诺而存在 - 实现编译是微不足道的,但是如果没有履行合同,它就没用了。 - Hulk


是MyList一个列表?

为了回答这个问题,你首先需要了解哪些接口做了什么或者他们为什么写的......

不要忘记接口可以为你提供一个非常重要的分类 能够 做和 怎么样 他们这样做...... 所以技术上实现一个接口不是要问一个对象 是一些东西 但更多的是要求 怎么样 一个物体可以做某事

所以当你说List myContainer = new ArrayList(); 你正在定义一个可以完成列表可以做的所有事情的对象...... 添加,删除,获取等等

你可以说它是一个列表,我会说它可以做列表可以做的事情..


0
2018-06-18 14:52