【问题标题】:Inner static class inside inner class cannot be converted无法转换内部类内部的内部静态类
【发布时间】:2013-06-30 11:20:41
【问题描述】:

受到这个问题的启发: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&lt;T&gt; implements Iterable&lt;T&gt; 和一个private static class Node&lt;T&gt; 和一个private class MyListIterator&lt;T&gt; implements Iterator&lt;T&gt;,但是在实现我自己的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);
    }
}

【问题讨论】:

标签: java generics static inner-classes


【解决方案1】:

MyListIterator的声明中去掉类型参数:

private class MyListIterator implements Iterator<T>

iterator()中的电话

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

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

【讨论】:

    【解决方案2】:

    这就是问题所在:

    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>
    

    (反之亦然)。

    【讨论】:

      【解决方案3】:

      迭代器应该声明为

      private class MyListIterator implements Iterator<T>
      

      而不是像

      private class MyListIterator<T> implements Iterator<T>
      

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

      【讨论】:

        【解决方案4】:

        其他三个是对的:你需要改变
        private class MyListIterator&lt;T&gt; implements Iterator&lt;T&gt;

        private class MyListIterator implements Iterator&lt;T&gt;
        但是一旦你这样做了,你还需要改变你的 iterator() 方法:

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

        否则你会得到另一个错误。进行第二次更改后,它应该可以工作。

        【讨论】:

        • 谢谢。我在进行更改时意识到了这一点:)。
        猜你喜欢
        • 1970-01-01
        • 2018-07-20
        • 2011-06-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-11-07
        • 2011-05-10
        相关资源
        最近更新 更多