人们通常承认,通过继承来扩展接口的实现并不是最佳实践,而组合(例如,从头开始再次实现接口)更易于维护。
这是有效的,因为接口契约强制用户实现所有所需的功能。然而,在 java 8 中,默认方法提供了一些可以“手动”覆盖的默认行为。考虑下面的例子:我想设计一个用户数据库,它必须具有列表的功能。出于效率目的,我选择通过 ArrayList 来支持它。
public class UserDatabase extends ArrayList<User>{}
这通常不会被认为是很好的实践,如果实际上想要列表的全部功能并遵循通常的“组合优于继承”的座右铭,人们会更喜欢:
public class UserDatabase implements List<User>{
//implementation here, using an ArrayList type field, or decorator pattern, etc.
}
但是,如果不注意,某些方法(例如 spliterator())将不需要重写,因为它们是 List 接口的默认方法。问题是,List 的 spliterator() 方法的性能比 ArrayList 的 spliterator() 方法差得多,后者已针对 ArrayList 的特定结构进行了优化。
这迫使开发商
- 请注意,ArrayList 有自己的、更高效的 spliterator() 实现,并手动覆盖其自己的 List 实现的 spliterator() 方法或
- 使用默认方法会损失大量性能。
所以问题是:在这种情况下,人们应该更喜欢组合而不是继承,这仍然是“正确的”吗?
在开始考虑性能之前,我们始终应该考虑正确性,即在您的问题中,我们应该考虑使用继承而不是委托意味着什么。这已经由这个 EclipseLink/JPA 问题 https://stackoverflow.com/a/26841569/2711488。由于继承的原因,如果延迟填充的列表尚未填充,则排序(同样适用于流操作)将不起作用。
因此,我们必须在专业化与新专业化之间进行权衡。default
方法,在继承情况下完全打破,并且有可能default
在委托情况下,方法不能发挥最大性能。我想,答案应该是显而易见的。
既然你的问题是关于新的default
方法change在这种情况下,应该强调的是,与以前甚至不存在的东西相比,您正在谈论性能下降。让我们留在sort
例子。如果您使用委派并且不覆盖default
排序方法,将default
方法的性能可能低于优化后的ArrayList.sort
方法,但在 Java 8 之前,后者不存在,并且算法未针对该方法进行优化ArrayList
是standard行为。
所以你不是loosingJava 8 下的委托性能,您只需没有获得更多,当你不覆盖default
方法。我想,由于其他改进,性能仍然会比 Java 7 下更好(没有default
方法)。
The Stream
API 不容易比较,因为 API 在 Java 8 之前并不存在。但是,很明显,类似的操作,例如如果你手动实现减少,除了通过Iterator
必须提防的贵国代表团名单remove()
尝试,因此包装ArrayList
Iterator
,或使用size()
and get(int)
哪个委托给支持者List
。所以不存在预default
方法 API 可以表现出比default
Java 8 API 的方法,因为没有ArrayList
- 无论如何,过去的具体优化。
也就是说,您的 API 设计可以通过使用来改进作品以不同的方式:不让UserDatabase
实施List<User>
根本不。只需提供List
通过访问器方法。然后,其他代码将不会尝试通过流式传输UserDatabase
实例,但在访问器方法返回的列表上。返回的列表可能是只读包装器 http://docs.oracle.com/javase/8/docs/api/java/util/Collections.html#unmodifiableList-java.util.List-它提供了最佳性能,因为它是由 JRE 本身提供的,并且会注意覆盖default
可行的方法。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)