Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cast is forced when using generics in Java

I wrote my own Stack class (for the relevant code, see below). In the next()-method I am forced to cast current.item to Item, but I do not know why. The type of current.item should already be Item and thus casting should not be necessary - but if I do not cast it, I get an error.

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

  private class Node {
      Item item;
      Node next;
  }

  private Node first= null;

  public Iterator<Item> iterator() { return new StackIterator(); }

  private class StackIterator<Item> implements Iterator<Item> {
    private Node current = first;

    public Item next(){
        Item item = (Item)current.item;
        current = current.next;
        return item;
    }
  }
}
like image 764
Mina Avatar asked Oct 16 '14 07:10

Mina


4 Answers

The type parameter from StackIterator<Item> hides the type Item, which is introduced in the definition of the Stack<Item> class.

This is why you need to do a cast (or to add a @SuppressWarnings("hiding") annotation).

In order to get rid of the warning, just remove the duplicated type:

private class StackIterator implements Iterator<Item> {

}
like image 173
Konstantin Yovkov Avatar answered Oct 17 '22 23:10

Konstantin Yovkov


You were using <Item> as a type parameter on both Stack and StackIterator, whereas what you really want to do is have StackIterator without a parameter and just state that it implements Iterator<Item>:

    private class StackIterator implements Iterator<Item> {
        private Node current = first;

        @Override
        public Item next() {
            Item item = current.item; // no need to cast now
            current = current.next;
            return item;
        }
    }
like image 41
Constantinos Avatar answered Oct 18 '22 00:10

Constantinos


Your class StackIterator is an inner class of Stack. That especially means that it is not static. Therefore it already knows about the type parameter Item.

You are doing the mistake of making the StackIterator having its own type parameter Item. This shadows the type parameter of the outer class.

So, simply remove the type parameter from StackIterator:

public class Stack<Item> implements Iterable<Item> {
    private class Node {
        Item item;
        Node next;
    }

    private Node first = null;

    @Override
    public Iterator<Item> iterator() { return new StackIterator(); }

    private class StackIterator implements Iterator<Item> {
        private Node current = Stack.this.first;

        @Override
        public Item next() {
            Item item = this.current.item;
            this.current = this.current.next;
            return item;
        }
    }
}
like image 3
Seelenvirtuose Avatar answered Oct 18 '22 01:10

Seelenvirtuose


If you want <Item> in StackIterator to be the same type as the enclosing <Item> associated with Stack, remove the declaration of <Item> in StackIterator.

If you want the <Item> in StackIterator to be different than the enclosing <Item> associated with Stack, but you want to be able to access properties of the parent Stack, rename <Item> to something else.

like image 1
ifloop Avatar answered Oct 18 '22 00:10

ifloop