什么是AbstractCollection的目的

9

AbstractCollection 实现了 Collection 接口。那么为什么会有 AbstractCollection 并且我们为什么使用 Collection 而不是直接使用 AbstractCollection 呢?


6
它不仅仅实现了Collection - Sotirios Delimanolis
AbstractCollection 一眼看去要少得多嘈杂。 - vikingsteve
1
通常,抽象实现定义了一些常见的功能,这些功能很可能会被大多数甚至所有其他实现使用,它们存在是为了让你的生活更轻松,但你不需要使用它。 - MadProgrammer
12
文档的第一行回答了你的问题:“该类提供了Collection接口的框架实现,以最小化实现该接口所需的工作量。” - Boann
2
@Boann 这意味着,一些集合实现将不会使用AbstractCollection,因为它们将提供自己的在Collection接口中定义的所有方法的实现。例如,Guava的ForwardingList - biziclop
抽象类向我们展示了如何实现接口的路径。 - Navdeep Singh
6个回答

5

也许回答有点晚,但以防万一我想回答这个问题。

  1. AbstractCollection被使用是因为所有的子集合都共享一些功能,就像Krzysztof所说的那样,由于这个功能是通用的(完全相同的代码行),我们可以使用继承来重用该代码并使设计更清晰、易于理解和更易于维护。

  2. 我们使用接口,因为接口定义了每个实现接口的类必须提供的“契约”,即 子类必须具有的方法。这个问题与为什么不能使用 ArrayList 而使用 List 类似,你可以这样做,但90%的时间你会对添加/设置、删除和知道 ArrayList 的大小感兴趣,而 List 接口确保你在 new 后编写的任何东西都将实现这些方法(和其他方法),因此你可以调用它们,并且多态性将起作用。此外,使用接口作为引用允许你更改具体实现的类型而不更改任何内容(仅更改 new 调用),还允许你在运行时更改具体类型,如果使用特定类的引用,则将自己限制在该引用和仅该引用上。


1

补充一下@Angelixus在https://dev59.com/XYTba4cB1Zd3GeqP2jBW#58513874中所说的:

不要这样做的一个原因是:

AbstractCollection col = (AbstractCollection) someCollection;

子类型的Collection并不保证扩展AbstractCollection基类。

当然,大多数(如果不是全部)标准集合类型确实扩展了这个基类。然而,这可能不适用于所有第三方集合类。如果你遇到一个没有扩展AbstractCollection的集合类,上述代码将根据someCollection声明类型产生编译错误或运行时异常。


1

Collection 接口声明了所有实现类必须提供的有用方法。但是,如果每个实现 Collection 接口的类都必须提供这么多方法,那就很麻烦。

为了让我们的生活更轻松,库提供了一个类 AbstractCollection,它将基本方法 sizeiterator 声明为抽象的,但通过这些方法来实现例行程序方法。例如:

public abstract class AbstractCollection<E>
    implements Collection<E>
{
    ...
    public abstract Iterator<E> iterator();
    public boolean contains(Object obj)
    {
        for (E element : this) // calls iterator()
            if (element.equals(obj))
                return true;
        return false;
    }
    ...
}

现在具体的集合类可以扩展AbstractCollection类。现在由我们来提供iterator方法,但是contains方法已经由AbstractCollection超类处理。然而,如果子类有更有效实现contains的方法,可以自由地这样做。但是这种方法有点过时了


0

这些类被称为框架实现类。命名规则是AbstractInterface,其中interface是接口的名称(例如-AbstractList)。它们是通过组合接口和抽象类创建的。

通常情况下,当我们设计一个接口并且接口方法有显然的实现时,我们可以在接口中提供默认方法,这样实现接口的人可以遵循默认实现,并在其上提供自定义实现。但是,在默认方法中提供的实现协助有限制。原因是接口不允许包含实例字段或非公共静态成员。但是,我们可以结合接口和抽象类的优点。

请参考下面的示例。假设我们有一个方法,该方法接受int数组并返回一个包含每个元素的平方的Integers列表。

public static List<Integer> squaredList(int [] e) {
    
    return new AbstractList<Integer>() {

        @Override
        public Integer get(int index) {
            return e[index] * e[index];
        }

        @Override
        public int size() {
            return e.length;
        }
    };
}

AbstractCollection,有2个方法是抽象的。如果您想要实现一个不可修改的集合,程序员只需要扩展此类并为迭代器和大小方法提供实现即可。(由iterator方法返回的迭代器必须实现hasNext和next。) 这种类型的实现在您实现具有返回Collection方法的不可变类时非常有用。

要实现可修改的集合,程序员还必须覆盖此类的add方法(否则会抛出UnsupportedOperationException),并且由iterator方法返回的迭代器还必须实现其remove方法。

有关详细信息,请参阅Java文档 https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/util/AbstractCollection.html


0

代码是最好的文档 :-) 可以在 JDK 中检查源代码,例如在 code-grep pages 中。

在那里,您可以看到,在 java 6b-14 中,AbstractCollection 类提供了 isEmpty()contains()toArray()toArray(T[] a)remove(Object o)containsAll(Collection<?> c)addAll(Collection<? extends E> c)removeAll(Collection<?> c)retainAll(Collection<?> c)clear()toString() 的直接实现。

上述方法取决于 add(E e)iterator() 和(可选)remove(Object o) 的实现。


0

以下是一段值得引用的有趣语录,来自Java核心技术 卷I:基础篇, 第10版

在Java API中,你会发现许多接口都有相应的实现类,例如Collection/AbstractCollection或者MouseListener/MouseAdapter。但在Java SE 8中,这种技术已经过时了。只需在接口中实现方法即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接