Ошибка компиляции реализации Java-коллекции - PullRequest
0 голосов
/ 18 февраля 2012

РЕДАКТИРОВАТЬ:

public class LinkedList<E> {
    private class Node {
        protected Node next, prev;
        protected E data;

        protected Node(E dat) {
            data = dat;
            next = prev = null;
        }
    }

    private Node head, tail;

    public LinkedList() {
        (head = new Node(null)).next = tail = new Node(null);
        tail.prev = head;
        tail.next = head.prev = null;

    }

    public class LinkedListIterator {
        private Node current = null;

        public synchronized void resetToHead() {
            current = head.next;
        }

        public synchronized void resetToTail() {
            current = tail.prev;
        }

        public synchronized E get() {
            if (current!=null) return current.data;
            return null;
        }
    }
}

проблема в том, что я получаю следующую ошибку компиляции в выделенных строках:

> Type mismatch: cannot convert from LinkedList<E>.Node<E> to
> LinkedList<E>.Node<E>

что это значит?и как мне это исправить?

Кстати, код является лишь частью реализации, поэтому не пытайтесь логически понять это.

Ответы [ 3 ]

2 голосов
/ 18 февраля 2012

--- Отредактировано, когда вопрос немного меняется ---

Теперь возникает вопрос: как мне два внутренних класса координировать универсальные типы?Короче говоря, им не нужно, если они оба являются внутренними классами внешнего класса, к которому привязан общий тип.Таким образом, даже с public synchronized E get() в неуниверсальном LinkedListIterator вы возвращаете E (и это безопасно для типов).

Однако, если вы затем дойдете до реализации java.util.Iterator<E>, вещи упадуткроме того, потому что это E основано на другом классе (интерфейсе), поэтому E имеет различную область видимости.Как вы это исправите?Вам необходимо параметризовать ваши Node классы в Node<E>, чтобы удовлетворять существующим привязкам E в реализации Iterator, даже если эта реализация используется вне области своего исходного класса.Это заставляет Node<E> быть статически определенным.

Причина, по которой статическое определение Node<E> связано с сборкой мусора.Итератор все еще может содержать ссылки на Node s, даже если LinkedList запланирован для сборки мусора.Конечно, вы могли бы предотвратить подобные вещи в конкретной реализации, но JVM должна разрешить любую реализацию (даже ошибочную).

Возможно, это легче объяснить с помощью кода

  public LinkedList<E> {

    public Iterator<E> iterator() {
      return new LinkedIterator(head);
    }

    // private because we don't want instances created outside of this LinkedList
    private class LinkedIterator implements Iterator<E> {

      // Right here, needing a parameterized next node will force Node to be static
      // static inner classes can exist outside of the scope of their parent
      // Since it can exist outside of the parent's scope, it needs it's own generic parameter
      private Node<E> next;

      LinkedIterator(Node start) {
        next = start;
      }

      public boolean hasNext() {
        return next != null;
      }

      public E next() {
        Node<E> retValue = next;
        if (retValue != null) {
          next = retValue.next;
        }
        return retValue;
      }

    }

    // must be static because LinkedList might be garbage collected when
    // an Iterator still holds the node.
    // This E is not the same E as in LinkedList, because it is a E declaration (hiding the above E)
    private static Node<E> {
      Node<E> next;
      Node<E> prev;
      E data;
    }

  }

Если вы не будете осторожны, теперь вы можете вернуться туда, откуда начали;однако ключ заключается в создании новых Node<E> объектов при необходимости в родительской области.Поскольку это та же область, в которой вы создаете типы LinkedIterator, безопасность общих типов будет обеспечена.

--- Исходная запись следует за ----

Указав, что определение класса вашего узлаNode<E>, вы в основном создаете второй универсальный тип с независимой областью действия E, который будет скрывать внешний универсальный тип E в классе LinkedList.

Поскольку ни один из ваших классов не является статическим, онибудет существовать только в контексте класса LinkedList, который обеспечит привязку обобщений.Это означает, что вы можете упростить Node<E> до Node, но при этом все равно помещать типы классов E в класс Node.То же самое касается LinkedListIterator, за исключением того, что если вы хотите, чтобы он реализовал Iterator, вы должны указать, что он реализует Iterator<E>.

По запросу, далее следует код, который компилируется на моей машине, (Java 1.6.0_20)

public class LinkedList<E> {

    private class Node {
        protected Node next, prev;
        protected E data;

        protected Node(E dat) {
            data = dat;
            next = prev = null;
        }
    }

    private Node head, tail;

    public LinkedList() {
        (head = new Node(null)).next = tail = new Node(null);
        tail.prev = head;
        tail.next = head.prev = null;

    }

    public class LinkedListIterator {
        private Node current = null;
        public synchronized void resetToHead() {
            current = head.next;
        }

        public synchronized void resetToTail() {
            current = tail.prev;
        }
    }
}
0 голосов
/ 18 февраля 2012

Не понятно, что в LinkedListIterator - это то же , что и родительский класс.Просто удалите из внутреннего класса:

    public class LinkedListIterator {
        private Node<E> current = null;

        public synchronized void resetToHead() {
            current = head.next;
        }

        public synchronized void resetToTail() {
            current = tail.prev;
        }
    }
0 голосов
/ 18 февраля 2012

Вы немного перестарались, параметризуя встроенные классы. Я удалил все ненужные.

public class LinkedList<E> {
    private class Node {
        protected Node next, prev;
        protected E data;

        protected Node(E dat) {
            data = dat;
            next = prev = null;
        }
    }

    private Node head, tail;

    public LinkedList() {
        (head = new Node(null)).next = tail = new Node(null);
        tail.prev = head;
        tail.next = head.prev = null;

    }

    public class LinkedListIterator {
        private Node current = null;

        public synchronized void resetToHead() {
        current = head.next;
        }

        public synchronized void resetToTail() {
            current = tail.prev;
        }
    }
}

Альтернативно с статическим классовым узлом.

public class LinkedList<E> {
    private static class Node<E2> {
        protected Node next, prev;
        protected E2 data;

        protected Node(E2 dat) {
            data = dat;
            next = prev = null;
        }
    }

    private Node<E> head, tail;

    public LinkedList() {
        (head = new Node(null)).next = tail = new Node(null);
        tail.prev = head;
        tail.next = head.prev = null;

    }

    public class LinkedListIterator {
        private Node<E> current = null;

        public synchronized void resetToHead() {
            current = head.next;
        }

        public synchronized void resetToTail() {
            current = tail.prev;
        }
    }
}
...