内部类中的内部静态类无法转换

时间:2013-07-02 22:06:52

标签: java generics static inner-classes

在这个问题中受到启发:How to implements Iterable我决定创建一个基本的链表实现并实现一个迭代器,以便得到这样的代码:

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

代码并不难处理,使用class MyList<T> implements Iterable<T>private static class Node<T>创建private class MyListIterator<T> implements Iterator<T>,但在实现我自己的Iterator#remove版本时遇到了问题1}}:

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;
            }
        }
    }
}

此错误消息引起了我的好奇心。我正在网上看到这个问题,但没有发现(或者我可能不太擅长搜索这类问题)。比较相同类型的两个变量但不能彼此分配的原因是什么?

顺便说一下,我知道我可以查看LinkedList的代码并检查Java设计者如何实现它并将其复制/粘贴/调整到我自己的实现中,但我更喜欢有一个解释并了解真正的问题。

完整代码,显示我当前MyList类的实现:

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);
    }
}

4 个答案:

答案 0 :(得分:16)

这是问题所在:

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

(在您的简化版本中,您使MyList非通用,这没有任何帮助。)

此时有两个不同的T类型变量 - 嵌套类中的变量和外部类中的变量。您不需要Node是通用的 - 您只需要:

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

现在只有一个 T - 外层的那个。你不希望列表迭代器与封闭实例中声明的不同 T,所以你不希望它是通用的。

换句话说:尝试在具有不同名称的类型参数中创建MyListIterator泛型,然后更清楚会出现什么问题,因为这两个名称在错误消息中是可区分的。这是有效的:

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

(反之亦然)。

答案 1 :(得分:7)

迭代器应声明为

private class MyListIterator implements Iterator<T>

而不是

private class MyListIterator<T> implements Iterator<T>

通过将其声明为MyListIterator,其泛型类型T与其封闭类中的T不同。

答案 2 :(得分:6)

MyListIterator

的声明中删除type参数
private class MyListIterator implements Iterator<T>

以及iterator()

中的来电
public Iterator<T> iterator() {
    return new MyListIterator(head);
}

在您当前的版本中,MyListIterator的T与MyList中的T不同。

答案 3 :(得分:2)

其他三个是对的:你需要改变
private class MyListIterator<T> implements Iterator<T>

private class MyListIterator implements Iterator<T>
但是一旦你这样做,你还需要改变你的iterator()方法:

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

否则你会收到另一个错误。一旦你做了第二次改变,它就应该有效。