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

8

受到这个问题的启发:如何实现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 时,遇到了问题:

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个回答

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>

(或反之)。

7
迭代器应该声明为:
private class MyListIterator implements Iterator<T>

而不是

private class MyListIterator<T> implements Iterator<T>

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

6

MyListIterator 的声明中删除类型参数:

private class MyListIterator implements Iterator<T>

并且在iterator()函数中调用

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

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

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

否则,您将会得到另一个错误。一旦您进行第二次更改,那么它应该就可以工作了。

谢谢。我在进行更改时已经知道了这个问题 :)。 - Luiggi Mendoza

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接