The inner static class inside the inner class cannot be converted

Inspired by this question: How to implement Iterable I decided to make a basic implementation of a linked list and implement an iterator to have code like this:

MyList<String> myList = new MyList<String>(); myList.add("hello"); myList.add("world"); for(String s : myList) { System.out.println(s); } 

It was not easy to compromise the code by creating the class MyList<T> implements Iterable<T> with private static class Node<T> and private class MyListIterator<T> implements Iterator<T> , but then I ran into a problem when implementing my own version of Iterator#remove :

 class MyList<T> implements Iterable<T> { private static class Node<T> { //basic node implementation... } private Node<T> head; private Node<T> tail; //constructor, add methods... private class MyListIterator<T> implements Iterator<T> { private Node<T> headItr; private Node<T> prevItr; public MyListIterator(Node<T> headItr) { this.headItr = headItr; } @Override public void remove() { //line below compiles if (head == headItr) { //line below compiles head = head.getNext(); //line below doesn't and gives me the message //"Type mismatch: cannot convert from another.main.MyList.Node<T> to //another.main.MyList.Node<T>" head = headItr.getNext(); //line below doesn't compile, just for testing purposes (it will be deleted) head = headItr; } } } } 

This error message aroused my curiosity. I looked on the net about this problem, but found nothing (or, probably, I am not so good at understanding such problems). What will be the reason for comparing two variables of the same type, but not assigned to each other?

By the way, I know that I can just look at the LinkedList code and check how the Java developers implemented this and copied / pasted / adapted it to my own implementation, but I prefer to have an explanation and understanding of the real problem.

Full code that shows my current implementation of the MyList class:

 class MyList<T> implements Iterable<T> { private static class Node<T> { private T data; private Node<T> next; public Node(T data) { super(); this.data = data; } public T getData() { return data; } public Node<T> getNext() { return next; } public void setNext(Node<T> next) { this.next = next; } } private Node<T> head; private Node<T> tail; private int size; public MyList() { head = null; tail = null; } public void add(T data) { Node<T> node = new Node<T>(data); if (head == null) { head = node; tail = head; } else { tail.setNext(node); tail = node; } size++; } private class MyListIterator<T> implements Iterator<T> { private Node<T> headItr; private Node<T> prevItr; public MyListIterator(Node<T> headItr) { this.headItr = headItr; } @Override public boolean hasNext() { return (headItr.getNext() != null); } @Override public T next() { T data = headItr.getData(); prevItr = headItr; if (hasNext()) { headItr = headItr.getNext(); } return data; } @Override public void remove() { if (head == headItr) { //problem here head = headItr.getNext(); } //implementation still under development... } } @Override public Iterator<T> iterator() { return new MyListIterator<T>(head); } } 
+8
java generics static inner-classes
source share
4 answers

This is the problem:

 class MyList<T> implements Iterable<T> { private class MyListIterator<T> implements Iterator<T> { ... } } 

(This will not help in your abridged version of the non-generic MyList you made.)

At this moment, there are two different variables of type T - one of the nested classes and one of the outer classes. You do not need Node be generic - you just need to:

 class MyList<T> implements Iterable<T> { private class MyListIterator implements Iterator<T> { ... } } 

Now there is only one T - one that is in the outer class. This is not like you want the list iterator to have a different T from the one declared in the instance, so you don't want it to be shared.

In other words: try making MyListIterator generic in the type parameter with a different name, and then it will be clearer what will go wrong, since the two names will be distinguishable in the error message. It is effective:

 Type mismatch: cannot convert from another.main.MyList.Node<TOuter> to another.main.MyList.Node<TInner> 

(or vice versa).

+16
source share

Iterator must be declared as

 private class MyListIterator implements Iterator<T> 

not like

 private class MyListIterator<T> implements Iterator<T> 

Having declared it as MyListIterator, its generic type T is not the same T as T from its encompassing class.

+7
source share

Remove type parameter from MyListIterator :

 private class MyListIterator implements Iterator<T> 

and call in iterator()

 public Iterator<T> iterator() { return new MyListIterator(head); } 

In your current version of T, MyListIterator does not match T in MyList .

+6
source share

The remaining three are correct: you need to change the private class MyListIterator<T> implements Iterator<T>
for image private class MyListIterator implements Iterator<T>
but as soon as you do this, you will also need to change your iterator() method:

 public Iterator<T> iterator() { return new MyListIterator(head); //was 'return new MyListIterator<T>();' } 

Or you will get another error. After you make the second change, it should work.

+2
source share

All Articles