在Java中,为什么在内部类上使用泛型不起作用?

时间:2016-04-27 13:02:58

标签: java generics types

我的编译器是JDK 6.0_65,以下是我的代码(Deque.java):

import java.util.Iterator;
public class Deque<Item> implements Iterable<Item> {
    private Node first;
    private Node last;

    private class Node {
        Item value;
        Node next;        
    }

    public Deque(){}                  // construct an empty deque

    public Iterator<Item> iterator() {
        // return an iterator over items in order from front to end
        return new DequeIterator<Item>();
    } 

    private class DequeIterator<Item> implements Iterator<Item> {
        private Node current = first;
        public boolean hasNext() {
            return current.next != null;
        }
        public Item next() {
            Item item = current.value;
            current = current.next;
            return item;
        }
        public void remove() {}

    }
    public static void main(String[] args)   {         
      // unit testing
        Deque<Integer> dq = new Deque<Integer>();

    }

}

在外部范围内:

public class Deque<Item> implements Iterable<Item> {

被使用。

在内在范围内:

private class DequeIterator<Item> implements Iterator<Item> {

被使用。

DequeIterator的范围内。我希望local-scope(内部类范围)Item将从Item隐藏类范围Deque<Item>

但是,在编译阶段,javac会抛出这样的错误:

Deque.java:2: error: incompatible types
            Item item = current.value;
                               ^
  required: Item#2
  found:    Item#1
  where Item#1,Item#2 are type-variables:
    Item#1 extends Object declared in class Deque
    Item#2 extends Object declared in class Deque.DequeIterator

它说Item#2Item#1是不兼容的类型,这对我来说很混乱,因为我已使用Item将类型参数DequeIterator传递到new DequeIterator<Item>()

有没有人对此有任何想法?

4 个答案:

答案 0 :(得分:7)

  

我希望本地范围(内部范围)Item会影响Deque<Item>

中的类范围项

这基本上就是发生的事情 - 内部范围Item遮蔽了外部范围。您已将外部Item传递给构造函数并不重要。内部类有编译问题,因为你试图将一个外部类型Item的值赋给一个内部类型的变量 - Item

要解决此问题,只需使嵌套类非通用:

private class DequeIterator implements Iterator<Item>

通过这种方式,您将使用外部 - Item而不声明您不需要的另一个Item类型参数。

答案 1 :(得分:3)

是内部类通用Item阴影通用的封闭类Item,这正是编译器抱怨的原因。你写了Item item=current.value(这就是问题所在)。这里Item引用内部类的泛型类型,但current.value是封闭类的泛型类型Item。这些类型不同!编译器将它们命名为Item#1Item#2。您只需从内部类DequeIterator中删除通用性:

public class Deque<Item> implements Iterable<Item> {
    private static class DequeIterator implements Iterator<Item> {
    }
}

答案 2 :(得分:1)

无法保证Item#1Item#2 总是相同。您可以将此类方法添加到Deque

public Iterator<Integer> boom() { 
    return new DequeIterator<Integer>();
}

这显然没有任何意义,但是因为迭代器类的Item与封闭类“Item s无关(因为内部Item类型参数阴影外部)它是完全合法的。

你没有理由给DequeIterator类一个类型参数,你可以简单地声明它:

private class DequeIterator implements Iterator<Item> {
    // Content remains unchanged
}

答案 3 :(得分:0)

试试这个,你甚至可以删除<T>

private class DequeIterator<T> implements Iterator<Item> {
    ...
}

我认为问题是某种阴影问题,其中内部和外部Item被认为是不同的。