【问题标题】:How to have Java Iterable return base subtype from extended generic如何让 Java Iterable 从扩展泛型返回基本子类型
【发布时间】:2018-01-10 08:06:43
【问题描述】:

我正在尝试创建一个子类 Iterable 的类。这类似于question。但是,我需要让列表中的对象成为特定类的子类,例如下面我的示例中的 QObject。另外,我需要我的迭代器实现ListIterator接口相关的具体方法。

问题是我实现 ListIterator 接口的内部类在我的实现中没有“返回”基本泛型类型 QObject。我做 QueueListIterator 泛型的方式有问题。

现在,如果我在示例代码中使用 Queue 声明 Queue,它可以工作。这必须提供允许迭代器正确获取类型所需的信息。但是,仅将其声明为 Queue 不会,即使基本泛型类型是 QObject 并且我在 Queue 类中的其他方法使用基本泛型类型。

那么,我的问题是为什么会发生这种情况,有没有办法指定 QueueListIterator 来识别基本泛型类型?

    public class Queue<T extends QObject> implements Iterable<T> {
        /**
         * The list of items in the queue.
         */
        protected List<T> myList;

        // other methods and defs

        public final Iterator<T> iterator() {
            return (new QueueListIterator());
        }

        public final ListIterator<T> listIterator() {
            return (new QueueListIterator());
        }

        private class QueueListIterator implements ListIterator<T> {

            protected ListIterator<T> myIterator;

            protected QueueListIterator() {
                myIterator = myList.listIterator();
            }

            @Override
            public void add(T o) {
                throw new UnsupportedOperationException("The method add() is not supported for Queue iteration");
            }

            @Override
            public boolean hasNext() {
                return myIterator.hasNext();
            }

            @Override
            public boolean hasPrevious() {
                return myIterator.hasPrevious();
            }

            @Override
            public T next() {
                return myIterator.next();
            }

            @Override
            public int nextIndex() {
                return myIterator.nextIndex();
            }

            @Override
            public T previous() {
                return myIterator.previous();
            }

            @Override
            public int previousIndex() {
                return myIterator.previousIndex();
            }

            @Override
            public void remove() {
                throw new UnsupportedOperationException("The method remove() is not supported for Queue iteration");
            }

            @Override
            public void set(T o) {
                throw new UnsupportedOperationException("The method set() is not supported for Queue iteration");
            }
        }
    }

    // testing code
    public static void test(){

            Queue q = new Queue();
            // put some stuff in the Queue
            QObject r1 = new QObject(q.getTime(), "A");
            q.enqueue(r1);
            QObject r2 = new QObject(q.getTime(), "B");
            q.enqueue(r2);

            // Does not work! 
            // incompatible object types, Object cannot be converted to QObject in the for( : ) construct
            for (QObject qo : q) {
                System.out.println(qo);
            }
    }

【问题讨论】:

  • 我编辑了这个问题,因为我的第一篇文章错过了 LT 和 GT 标志。是的, Queue q 确实提供了必要的类型信息。但是,我相信如果我对获取 QObjects 没问题,我不应该在声明队列时提供基本泛型类型
  • 这只是你使用泛型的一个问题。应该是Queue&lt;QObject&gt; q = new Queue&lt;QObject&gt;()。
  • 我了解 Queue 的工作原理。但是,如果我只是将队列声明为 Queue q = new Queue(),那么我的其他方法(未显示)例如 T removeFirst() 将获得通用基类型 QObject 而不会从声明中提供,因为他们知道类型 T 必须是 QObject 的子类型。但是,我无法让 Iteratable 做同样的事情。
  • 是的。根本没有办法让它发挥作用。但是你不应该担心它,因为无论如何你都不应该在没有类型参数的情况下使用Queue。
  • 路易斯,我现在同意。我现在必须更多地研究泛型类型系统。

标签: java generics iteration


【解决方案1】:

使用原始类型 Queue 与使用擦除 Queue 相同。 T removeFirst() 允许您检索 QObject 但 Iterator.next() 不能检索的原因是 T removeFirst() 和 Iterator&lt;T&gt; iterator() 擦除方式不同。类型变量的擦除是它最左边的边界的擦除,所以T擦除到QObject,但是参数化类型的擦除是没有任何类型参数的类型,所以Iterator&lt;T&gt;擦除到Iterator . (source)

没有办法让它与原始类型一起使用,您应该改用Queue&lt;QObject&gt;。在某些情况下,您还可以使用Queue&lt;?&gt; 作为引用类型。 (见PECS。)

另见What is a raw type and why shouldn't we use it?

【讨论】:

  • 这很有帮助,尽管令人失望。应该让我的内部类以我想要的方式了解基本泛型类型,这似乎是合理的。但是,理解不应使用原始类型表明我对类型系统的基本误解。现在有点清楚了。
【解决方案2】:

如果你这样声明 q 会怎样: 队列q

【讨论】:

  • 这是评论,不是答案。
  • 我认为这是一个评论,而不是一个答案。我原来的帖子已经指出这会起作用。
猜你喜欢
  • 2018-07-13
  • 1970-01-01
  • 2017-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-06
  • 1970-01-01
  • 2021-03-25
相关资源
最近更新 更多