1

My compiler is JDK 6.0_65, and following are my codes (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>();

    }

}

In the outer scope :

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

is used.

And in the inner scope:

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

is used.

In the scope of DequeIterator. I expected the local-scope (inner-class-scope) Item will shadow the class-scope Item from Deque<Item>.

However, during compiling stage, javac will throw an error like this:

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

It says Item#2 and Item#1 is incompatible types, which looks quite confusing to me because I have passed the type parameter Item into DequeIterator using new DequeIterator<Item>().

Does anyone have any idea about this?

rajah9
  • 11,645
  • 5
  • 44
  • 57
Hanfei Sun
  • 45,281
  • 39
  • 129
  • 237
  • `Deque` is a class name (well, an interface) already used by the JDK; it is not a very good idea to reuse that... – fge Apr 27 '16 at 13:05
  • 2
    Just as Node is not parametrised with (a new) Item do not introduce a new Item here, or else rename it. Remove the `` from DequeueIterator there. – Joop Eggen Apr 27 '16 at 13:05

4 Answers4

7

I expected the local-scope (inner-class-scope) Item will shadow the class-scope Item from Deque<Item>

This is basically precisely what happened - the inner-scope Item shadowed the outer one. It does not matter that you've passed the outer Item to the constructor. The inner class has problems compiling because you're trying to assign a value of type outer-Item to a variable of type inner-Item.

To fix this just make the nested class non-generic:

private class DequeIterator implements Iterator<Item>

In that way you will use the outer-Item without declaring another Item type parameter which you don't really need.

Paweł Motyl
  • 1,304
  • 10
  • 16
3

Yes inner class generic Item shadows generic enclosing class Item, this is exactly why the compiler complains. You wrote Item item=current.value (and that is the problem). Here Item refers to the generic type of the inner class, but current.value is of generic type Item of the enclosing class. These types are different! The compiler named them Item#1 and Item#2. You just have to remove the genericity from inner class DequeIterator:

public class Deque<Item> implements Iterable<Item> {
    private static class DequeIterator implements Iterator<Item> {
    }
}
Jean-Baptiste Yunès
  • 34,548
  • 4
  • 48
  • 69
1

There's no guarantee that Item#1 and Item#2 will always be the same. You could add a method like this to Deque:

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

This obviously doesn't make any sense, but since the Items of the iterator class aren't related to the enclosing class' Items (because the inner Item type parameter shadows the outer) it's perfectly legal.

There's no reason for you to give the DequeIterator class a type parameter though, you can simply declare it thus:

private class DequeIterator implements Iterator<Item> {
    // Content remains unchanged
}
gustafc
  • 28,465
  • 7
  • 73
  • 99
0

Try this, and you may even remove the <T>:

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

I think the problem is some sort of shadowing problem where the inner and outer Item are considered different.

totoro
  • 2,469
  • 2
  • 19
  • 23