2016-04-27 3 views
1

Mein Compiler ist JDK 6.0_65 und folgenden sind meine Codes (Deque.java):Warum funktioniert die Verwendung von generic für eine innere Klasse in Java nicht?

import java.util.Iterator; 
public class Deque<Item> implements Iterable<Item> { 
    private Node first; 
    private Node last; 

    private class Node { 
     Item value; 
     Node next;   
    } 

    public Deque(){}     // construct an empty deque 

    public Iterator<Item> iterator() { 
     // return an iterator over items in order from front to end 
     return new DequeIterator<Item>(); 
    } 

    private class DequeIterator<Item> implements Iterator<Item> { 
     private Node current = first; 
     public boolean hasNext() { 
      return current.next != null; 
     } 
     public Item next() { 
      Item item = current.value; 
      current = current.next; 
      return item; 
     } 
     public void remove() {} 

    } 
    public static void main(String[] args) {   
     // unit testing 
     Deque<Integer> dq = new Deque<Integer>(); 

    } 

} 

Im Außenbereich:

public class Deque<Item> implements Iterable<Item> { 

verwendet wird.

Und im Innenbereich:

private class DequeIterator<Item> implements Iterator<Item> { 

verwendet wird.

Im Rahmen von DequeIterator. Ich habe erwartet, dass der local-scope (inner-class-scope) Item den Class-scope Item von Deque<Item> abschirmen wird.

jedoch während der ersten Stufe Kompilieren javac einen Fehler wie diese werfen:

Deque.java:2: error: incompatible types 
      Item item = current.value; 
          ^
    required: Item#2 
    found: Item#1 
    where Item#1,Item#2 are type-variables: 
    Item#1 extends Object declared in class Deque 
    Item#2 extends Object declared in class Deque.DequeIterator 

Es sagt Item#2 und Item#1 inkompatible Typen ist, die mir ziemlich verwirrend aussieht, weil ich den Typ-Parameter Item in DequeIterator bestanden haben mit new DequeIterator<Item>().

Hat jemand eine Ahnung davon?

+0

'Deque' ist ein Klassenname (na ja, eine Schnittstelle), die bereits durch das JDK verwendet ; es ist keine sehr gute Idee, das wiederzuverwenden ... – fge

+2

Genauso wie Node nicht mit (einem neuen) Item parametrisiert wird, darf hier kein neues Item eingefügt oder umbenannt werden. Entfernen Sie das '' von DequeueIterator dort. –

Antwort

6

erwartete ich den lokalen Rahmen (Innenklasse-scope) Item werden die Klasse-scope Artikel von Deque<Item>

Schatten Dies ist im Grunde genau das, was passiert ist - der innere Umfang Item die äußerte beschattete ein. Es spielt keine Rolle, dass Sie den äußeren Item an den Konstruktor übergeben haben. Die innere Klasse hat Probleme beim Kompilieren, weil Sie versuchen, einen Wert vom Typ outer-Item einer Variablen vom Typ inner- Item zuzuweisen.

Um dies zu beheben nur die verschachtelte Klasse nicht-generic machen: Auf diese Weise

private class DequeIterator implements Iterator<Item> 

erhalten Sie die Aussen- Item ohne Deklaration eines anderen Item Typ-Parameter verwenden, die Sie nicht wirklich brauchen.

0

die Sie interessieren, und Sie können sogar die <T> entfernen:

private class DequeIterator<T> implements Iterator<Item> { 
    ... 
} 

Ich denke, das Problem ist, eine Art Schatten Problem, bei dem die inneren und äußeren Item betrachtet unterschiedlich.

3

Ja innere Klasse generische Item Schatten generische umschließende Klasse Item, das ist genau, warum der Compiler beklagt. Du hast Item item=current.value geschrieben (und das ist das Problem). Hier bezieht sich Item auf den generischen Typ der inneren Klasse, aber current.value ist vom generischen Typ Item der umschließenden Klasse. Diese Typen sind anders! Der Compiler nannte sie Item#1 und Item#2.Sie müssen nur die Generizität von innerer Klasse DequeIterator entfernen: keine Garantie

public class Deque<Item> implements Iterable<Item> { 
    private static class DequeIterator implements Iterator<Item> { 
    } 
} 
1

Es ist die Item#1 und Item#2 werden immer gleich sein. Sie könnten eine Methode wie folgt zu Deque hinzufügen:

public Iterator<Integer> boom() { 
    return new DequeIterator<Integer>(); 
} 

dies offensichtlich keinen Sinn macht, aber da die Item s der Iterator-Klasse sind mit der umgebenden Klasse nicht verbunden sind Item s (weil der Innen Item Typ Parameter Schatten der äußeren) es ist völlig legal.

Es gibt keinen Grund für Sie, die DequeIterator Klasse ein Typparameter obwohl zu geben, können Sie es einfach erklären also:

private class DequeIterator implements Iterator<Item> { 
    // Content remains unchanged 
} 
Verwandte Themen