简体   繁体   English

为什么Java中的许多Collection类都会扩展抽象类并实现接口?

[英]Why do many Collection classes in Java extend the abstract class and implement the interface as well?

Why do many Collection classes in Java extend the Abstract class and also implement the interface (which is also implemented by the given abstract class)? 为什么Java中的许多Collection类都扩展Abstract类并实现接口(也由给定的Abstract类实现)?

For example, class HashSet extends AbstractSet and also implements Set , but AbstractSet already implements Set . 例如,类HashSet扩展了AbstractSet并实现了Set ,但是AbstractSet已经实现了Set

It's a way to remember that this class really implements that interface. 这是记住此类真正实现该接口的一种方式。
It won't have any bad effect and it can help to understand the code without going through the complete hierarchy of the given class. 它不会有任何不良影响,并且可以帮助您理解代码,而无需遍历给定类的完整层次结构。

From the perspective of the type system the classes wouldn't be any different if they didn't implement the interface again, since the abstract base classes already implement them. 从类型系统的角度来看,如果类没有再次实现该接口,它们将没有任何不同,因为抽象基类已经实现了它们。

That much is true. 那是真的。

The reason they do implement it anyways is (probably) mostly documentation: a HashSet is-a Set . 他们反正实现它的原因是(可能)主要文件:一个HashSet是,一个Set And that is made explicit by adding implements Set to the end, although it's not strictly necessary. 通过添加implements Set到末尾,这是明确的,尽管这不是绝对必要的。

Note that the difference is actually observable using reflection, but I'd be hard-pressed to produce some code that would break if HashSet didn't implement Set directly. 请注意,使用反射实际上可以观察到这种差异,但是如果HashSet不直接实现Set ,我将很难产生一些会中断的代码。

This may not matter much in practice, but I wanted to clarify that explicitly implementing an interface is not exactly the same as implementing it by inheritance. 在实践中,这可能无关紧要,但是我想澄清一下,显式实现接口与通过继承实现接口并不完全相同 The difference is present in compiled class files and visible via reflection. 差异存在于编译的类文件中,并且可以通过反射看到。 Eg, 例如,

for (Class<?> c : ArrayList.class.getInterfaces())
    System.out.println(c);

The output shows only the interfaces explicitly implemented by ArrayList , in the order they were written in the source, which [on my Java version] is: 输出仅显示由ArrayList 显式实现的接口,按在源中编写的顺序排列(在我的Java版本中)为:

interface java.util.List
interface java.util.RandomAccess
interface java.lang.Cloneable
interface java.io.Serializable

The output does not include interfaces implemented by superclasses, or interfaces that are superinterfaces of those which are included. 输出不包括由超类实现的接口,也不是作为所包含接口的超接口的接口。 In particular, Iterable and Collection are missing from the above, even though ArrayList implements them implicitly. 特别是,即使ArrayList隐式实现了它们,上述内容中也缺少IterableCollection To find them you have to recursively iterate the class hierarchy. 要找到它们,您必须递归地迭代类层次结构。

It would be unfortunate if some code out there uses reflection and depends on interfaces being explicitly implemented, but it is possible, so the maintainers of the collections library may be reluctant to change it now, even if they wanted to. 不幸的是,那里的某些代码使用反射并依赖于显式实现的接口,但是这是可能的,因此collections库的维护者可能不愿意现在更改它,即使他们愿意。 (There is an observation termed Hyrum's Law : "With a sufficient number of users of an API, it does not matter what you promise in the contract; all observable behaviors of your system will be depended on by somebody".) (有一个称为Hyrum定律的观察:“使用足够多的API用户,您在合同中承诺的内容并不重要;系统的所有可观察到的行为将取决于某人”。)

Fortunately this difference does not affect the type system. 幸运的是,这种差异不会影响类型系统。 The expressions new ArrayList<>() instanceof Iterable and Iterable.class.isAssignableFrom(ArrayList.class) still evaluate to true . new ArrayList<>() instanceof IterableIterable.class.isAssignableFrom(ArrayList.class) new ArrayList<>() instanceof Iterable表达式的计算结果仍为true

Unlike Colin Hebert , I don't buy that people who were writing that cared about readability. Colin Hebert不同的是,我不买那些关心可读性的人。 (Everyone who thinks standard Java libraries were written by impeccable gods, should take look it their sources. First time I did this I was horrified by code formatting and numerous copy-pasted blocks.) (每个认为标准Java库是由无可挑剔的神编写的人,都应该看一下它们的源代码。第一次这样做时,我对代码格式和众多复制粘贴的块感到震惊。)

My bet is it was late, they were tired and didn't care either way. 我敢打赌,这已经很晚了,他们很累,一点也不在乎。

From the "Effective Java" by Joshua Bloch: 摘自Joshua Bloch的“有效Java”:

You can combine the advantages of interfaces and abstract classes by adding an abstract skeletal implementation class to go with an interface. 您可以通过添加抽象骨架实现类和接口一起来结合接口和抽象类的优点。

The interface defines the type, perhaps providing some default methods, while the skeletal class implements the remaining non-primitive interface methods atop the primitive interface methods. 接口定义类型,可能提供一些默认方法,而骨架类在原始接口方法之上实现其余的非原始接口方法。 Extending a skeletal implementation takes most of the work out of implementing an interface. 扩展骨架实现可以使大部分工作脱离实现接口。 This is the Template Method pattern. 这是模板方法模式。

By convention, skeletal implementation classes are called AbstractInterface where Interface is the name of the interface they implement. 按照惯例, 骨架实现类称为AbstractInterface ,其中Interface是它们实现的接口的名称。 For example: 例如:

AbstractCollection
AbstractSet
AbstractList
AbstractMap

I also believe it is for clarity. 我也相信这是为了清楚。 The Java Collections framework has quite a hierarchy of interfaces that defines the different types of collection. Java Collections框架具有相当的接口层次结构,用于定义不同类型的集合。 It starts with the Collection interface then extended by three main subinterfaces Set, List and Queue. 它从Collection接口开始,然后由三个主要子接口Set,List和Queue扩展。 There is also SortedSet extending Set and BlockingQueue extending Queue. 还有SortedSet扩展Set和BlockingQueue扩展Queue。

Now, concrete classes implementing them is more understandable if they explicitly state which interface in the heirarchy it is implementing even though it may look redundant at times. 现在,如果具体类明确声明其正在实现的层次结构中的哪个接口,尽管具体类有时看起来可能很多余,但实现起来更容易理解。 As you mentioned, a class like HashSet implements Set but a class like TreeSet though it also extends AbstractSet implements SortedSet instead which is more specific than just Set. 如您所述,像HashSet这样的类可以实现Set,但是像TreeSet这样的类虽然可以扩展AbstractSet,但它可以实现SortedSet,而不仅仅是Set。 HashSet may look redundant but TreeSet is not because it requires to implement SortedSet. HashSet可能看起来很多余,但TreeSet却不是,因为它需要实现SortedSet。 Still, both classes are concrete implementations and would be more understandable if both follow certain convention in their declaration. 仍然,这两个类都是具体的实现,并且如果它们在声明中都遵循某些约定,则将更易于理解。

There are even classes that implement more than one collection type like LinkedList which implements both List and Queue. 甚至有一些类实现了多个集合类型,例如LinkedList,它同时实现了List和Queue。 However, there is one class at least that is a bit 'unconventional', the PriorityQueue. 但是,PriorityQueue至少有一个类有点“非常规”。 It extends AbstractQueue but doesn't explicitly implement Queue. 它扩展了AbstractQueue,但未明确实现Queue。 Don't ask me why. 不要问我为什么。 :) :)

(reference is from Java 5 API) (参考来自Java 5 API)

In my view,when a class implements an interface it has to implement all methods present in it(as by default they are public and abstract methods in an interface). 在我看来,当一个类实现一个接口时,它必须实现其中存在的所有方法(默认情况下,它们是接口中的公共方法和抽象方法)。

If we don't want to implement all methods of interface,it must be an abstract class. 如果我们不想实现所有的接口方法,则它必须是一个抽象类。

So here if some methods are already implemented in some abstract class implementing particular interface and we have to extend functionality for other methods that have been unimplemented,we will need to implement original interface in our class again to get those remaining set of methods.It help in maintaining the contractual rules laid down by an interface. 因此在这里,如果某些方法已经在实现特定接口的抽象类中实现了某些方法,并且我们必须扩展尚未实现的其他方法的功能,那么我们将需要在类中再次实现原始接口以获取其余的方法集。维护界面制定的合同规则。

It will result in rework if were to implement only interface and again overriding all methods with method definitions in our class. 如果仅实现接口,并且再次在我们的类中使用方法定义覆盖所有方法,则将导致返工。

Too late for answer? 来不及回答?

I am taking a guess to validate my answer. 我正在猜测以验证我的答案。 Assume following code 假设以下代码

HashMap extends AbstractMap (does not implement Map) HashMap extends AbstractMap (不实现Map)

AbstractMap implements Map

Now Imagine some random guy came, Changed implements Map to some java.util.Map1 with exactly same set of methods as Map 现在,想象一下一个随机的家伙来了,Changed使用与Map完全相同的方法集将Map实现到某些java.util.Map1

In this situation there won't be any compilation error and jdk gets compiled (off course test will fail and catch this). 在这种情况下,不会有任何编译错误并且jdk会被编译(当然测试会失败并捕获此错误)。

Now any client using HashMap as Map m= new HashMap() will start failing. 现在,任何将HashMap用作Map m = new HashMap()的客户端都将开始失败。 This is much downstream. 这在下游。

Since both AbstractMap, Map etc comes from same product, hence this argument appears childish (which in all probability is. or may be not.), but think of a project where base class comes from a different jar/third party library etc. Then third party/different team can change their base implementation. 由于AbstractMap和Map等都来自同一产品,因此该参数看起来很幼稚(很可能是或可能不是),但请考虑一个项目,其中基类来自其他jar /第三方库等。第三方/不同的团队可以更改其基本实施方式。

By implementing the "interface" in the Child class, as well, developer's try to make the class self sufficient, API breakage proof. 同样,通过在Child类中实现“接口”,开发人员试图使该类自成体系,并证明API不会损坏。

I suppose there might be a different way to handle members of the set, the interface, even when supplying the default operation implementation does not serve as a one-size-fits-all. 我想,即使提供默认的操作实现并不能一劳永逸,也可能有其他方法来处理集合的成员(接口)。 A circular Queue vs. LIFO Queue might both implement the same interface, but their specific operations will be implemented differently, right? 循环队列与LIFO队列可能都实现相同的接口,但是它们的特定操作将以不同的方式实现,对吗?

如果您只有一个抽象类,那么您将无法创建自己的类,而该类也将从另一个类继承。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 java 的抽象 class 中实现接口和扩展线程 - How to implement interface AND extend a thread in an abstract class in java 在Intellij IDEA中,找到实现接口但不扩展另一个类的类 - In Intellij IDEA, find classes that implement an interface but do not extend another class 抽象类是否需要在Java 7中实现整个接口? - Do Abstract classes need to implement an entire interface in java 7? Java类设计-最佳方法的建议。 类扩展抽象类并实现接口 - Java Class design - Advice for best approach. Class extend abstract class and implement interface 为什么抽象类不能扩展接口? - Why can't an abstract class extend an interface? Java:强制实现接口以扩展抽象类 - Java: Force implementation of interface to extend abstract class 如何实现Java Enumeration Abstract类和接口? - How do you implement a Java Enumeration Abstract class and interface? Java-获取扩展抽象类的所有类 - Java - Getting all the classes that extend an Abstract Class 为什么大多数Java框架类都扩展可序列化接口? - Why do most of the classes of Java frameworks extend serializable interface? 为什么实现接口的类不算与Java中的接口类型相同? - Why do classes that implement an interface not count as the same type as the interface in Java?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM