如何让Java接口具有HAS-A关系

9 浏览
0 Comments

如何让Java接口具有HAS-A关系

我正在从一个教程中学习Java集合框架,它说Iterator接口与Collection接口有HAS-A关系,这为Collection类提供了向前遍历的功能。\n而ListIterable接口是Iterator接口的子接口,它与List接口有HAS-A关系,并且只为列表类提供向后遍历的功能。\n如果有人能够友好地解释一下接口之间的HAS-A关系是如何工作的,或者我是不是在学习错了?谢谢。

0
0 Comments

Java接口如何拥有HAS-A关系的问题出现的原因是因为关于接口关系的陈述是过于简化的。实际上,HAS-A关系是在实现类之间建立的。如果接口设计得以一种方式,使得所有的实现类都始终建立一个HAS-A关系,那么我们可以说接口之间存在HAS-A关系。

对于Iterator接口来说,并不总是存在HAS-A关系。一个接口可以通过声明至少一个依赖于其他对象的方法(例如一个访问器方法)来建立一个始终存在的HAS-A关系。然而,它仍然无法强制实现类以预期的方式实现它。例如,一个实现类可以通过始终抛出异常来实现这个方法。但是,如果接口的契约暗示存在HAS-A关系,我们可以忽略违反契约的实现。

对于Iterator接口来说,它没有访问器方法,但是有一个被称为remove()的方法,它被假定会影响源集合。但是这个方法被标记为可选操作,并且明确允许抛出UnsupportedOperationException异常。因此,虽然迭代器实现通常与它所创建的集合具有HAS-A关系,但并非总是如此。

一个反例是CopyOnWriteArrayList。当你在它上面调用iterator()方法时,返回的迭代器将与底层数组具有HAS-A关系。因此,在迭代器创建时,集合和迭代器都与该数组具有HAS-A关系,但是当你修改集合时,它将与一个新的数组建立HAS-A关系,所以在修改后,迭代器和集合完全解耦。

此外,并不是每个迭代器都源自于一个集合。例如:

Iterator i = Collections.emptyIterator();

Iterator i = IntStream.range(0, 10).iterator();

请参阅Collections.emptyIterator()和BaseStream.iterator()。

注意,对于某些情况,尤其是不可变集合,我们可以说迭代器在概念上与集合具有HAS-A关系,因为它们提供对其内容的访问,即使以不同的方式实现。这就是为什么上面的例子被谨慎选择来反驳该陈述的概念层面,要么是因为没有集合,要么是因为集合在修改时明确地与迭代器解耦。

因此,尽管接口之间不直接建立HAS-A关系,但在某些情况下,可以通过接口的设计和实现来实现这种关系。

0