有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

Java的集合接口和类层次结构是否做得不好?

我知道在Java中,^{} class implements both ^{} and ^{}接口。 这让我有些困惑

在计算机科学教学大纲中,我从未被教导队列可以是一个列表,或者更准确地说,队列可以像一个列表一样工作。也就是说,列表可以做一些事情,但是队列不能。但是列表可以像队列一样工作。例如,List接口有the following methods

add(E e)
add(int index, E element)

但是Queue{a3}

add(E e)

所以显然Queue不允许在特定索引处插入,这在List中是允许的。其他操作的情况也是如此,比如Queue.remove()List.remove(int index)List.get(int index)Queue.peek()。 换句话说,list是一种更通用的数据结构,可以模拟Queue

现在,能够模仿与拥有契约子集是不同的。也就是说,Queue不允许对List进行某些操作(索引),并且只允许以特定方式进行某些操作(仅在尾部插入,仅从头部移除)。所以Queue并不是真的对List的合同进行“添加”。这正是为什么Queue在Java集合框架中不扩展List,而是扩展Collection接口的原因。我认为,这也是为什么任何类都不能同时实现这两个方面,因为Queue的契约与List的契约冲突(这就是为什么它们分别从Collection接口分叉)。然而,LinkedList实现了这两个接口

我还遇到了this答案:

The LinkedList implementation happens to satisfy the Deque contract, so why not make it implement the interface?

我仍然不明白我们怎么能说“LinkedList实现恰好满足了Deque契约”。队列的概念不允许在任意索引处插入。因此,Queue接口没有这样的方法

然而,我们只能通过接口执行合同,不能禁止某些方法的实现。作为list(名称中有“list”),我觉得在peek()pop()add(int index, E element)中有队列方法是不正确的

我认为,相反,我们应该有单独的类LinkedQueue,它可以有队列的链接实现,类似于LinkedBlockingQueue,它包含BlockingQueue的链接实现

还要注意LinkedList是从列表和队列家族继承的唯一类,也就是说,没有其他类同时实现ListQueue(AFAIK)。这是否表明LinkedList做得不好

我是不是完全错了,想得不必要


共 (1) 个答案

  1. # 1 楼答案

    LinkedList是一个类,实现了ListDeque接口。这些接口中的每一个都定义了一个包含操作的契约,并且在这些契约中指定了这些操作必须执行的操作。但是,没有明确说明这些操作应该如何工作

    LinkedList是一个类,实现了ListDeque接口。因此,尽管后缀ListLinkedList类名称的一部分,但LinkedList实际上既是List又是Deque,因为它实现了ListDeque接口中定义的所有操作

    所以LinkedList是一个a List,它也是一个{}。这并不意味着List应该是Deque,或者Deque应该是List

    例如,查看以下界面:

    public interface BloodDrinker {
    
        void drinkBlood();
    }
    
    public interface FlyingInsect {
    
        void flyAround();
    }
    

    上面的每个接口都有一个操作,并定义了一个契约。drinkBlood操作定义了BloodDrinker必须做什么,但没有定义如何做。这同样适用于FlyingInsect:它的flyAround操作定义了它必须做什么,而不是如何做

    现在考虑^ {CD25>}类:

    public class Mosquito implements FlyingInsect, BloodDrinker {
    
        public void flyAround() {
            // fly by moving wings, 
            // buzzing and bothering everyone around
        }
    
        public void drinkBlood() {
            // drink blood by biting other animals:
            // suck their blood and inject saliva
        }
    }
    

    现在,这意味着一个Mosquito既是一个FlyingInsect又是一个BloodDrinker,但是为什么一个嗜血者必然是一个飞虫,或者一个飞虫必然是一个嗜血者呢?例如,吸血鬼是吸血鬼,但不是飞虫,而蝴蝶是飞虫,但不是吸血鬼


    现在,关于你关于Queue不允许某些List的操作(索引),并且只允许以FIFO方式在其末端添加/删除的论点。。。我认为这一基本原理是不正确的,至少在Java集合框架的上下文中是这样The contract of ^{}没有明确提到实现者永远无法在任何给定的索引中添加/删除/检查元素。它只是说Deque是:

    A linear collection that supports element insertion and removal at both ends.

    它还说:

    This interface defines methods to access the elements at both ends of the deque.

    (我的)

    几段之后,它明确表示:

    Unlike the List interface, this interface does not provide support for indexed access to elements.

    (再次强调我的观点)

    这里的关键部分是不提供支持。它从不禁止实现者通过索引访问元素。只是通过Deque接口不支持索引访问

    想想我上面的例子:为什么a BloodDrinker会禁止其实现者喝血液以外的东西,即水?或者为什么a FlyingInsect会禁止其实现者以不同于飞行的方式移动,即步行

    归根结底,一个实现可以按照自己的意愿遵守任意多个契约,只要这些契约彼此不矛盾。正如用Java编写的一样(我必须承认,这是一个非常谨慎而微妙的措辞),Deque的契约与List的契约并不矛盾,因此可以完美地存在一个实现两个接口的类,而这个类恰好是LinkedList