2010-04-09 13 views
9

Ho un problema durante la compilazione di una classe generica con una classe interna. La classe estende una classe generica, anche la classe interiore.Errore di compilazione sull'ereditarietà della classe interna generica che si estende con i limiti

Qui l'interfaccia implementata:

public interface IndexIterator<Element> 
    extends Iterator<Element> 
{ 
    ... 
} 

classe Super generica:

public abstract class CompoundCollection<Element, Part extends Collection<Element>> 
    implements Collection<Element> 
{ 
    ... 

    protected class CompoundIterator<Iter extends Iterator<Element>> 
     implements Iterator<Element> 
    { 
    ... 
    } 
} 

La sottoclasse generica con l'errore del compilatore:

public class CompoundList<Element> 
    extends CompoundCollection<Element, List<Element>> 
    implements List<Element> 
{ 
    ... 

    private class CompoundIndexIterator 
     extends CompoundIterator<IndexIterator<Element>> 
     implements IndexIterator<Element> 
    { 
    ... 
    } 
} 

L'errore è:

type parameter diergo.collect.IndexIterator<Element> is not within its bound 
     extends CompoundIterator<IndexIterator<Element>> 
              ^

Cosa c'è che non va? Il codice viene compilato con eclipse, ma non con il compilatore java 5 (utilizzo formica con java 5 su mac ed eclipse 3.5). No, non posso convertirlo in una classe interna statica.

+1

Qualche possibilità di provarlo con Java 6?Potrebbe essere un bug del compilatore. –

+0

Appena provato con Java 6. Stesso messaggio di errore. Interessante ... –

+0

@mmyers: buona idea @Eval: grazie, ho provato anche io sul mac 1.6 jdk - stesso errore –

risposta

8

Il Java Language Specification, §8.1.3, definisce la semantica di sottoclasse tipi interne come segue :

Furthermore, for every superclass S of C which is itself a direct inner class of a class SO, there is an instance of SO associated with i, known as the immediately enclosing instance of i with respect to S. The immediately enclosing instance of an object with respect to its class' direct superclass, if any, is determined when the superclass constructor is invoked via an explicit constructor invocation statement.

noti che l'istanza racchiude viene descritto solo per essere di una particolare classe , non un particolare tipo . Come tutte le istanze di un tipo di quota generica della stessa classe, il codice seguente sarebbe legale:

class Base<E> { 
    E e; 

    protected class BaseInner<I extends E>{ 
     E e() { return e; } 
    } 
} 

class StrangeSub extends Base<Integer> { 
    protected class StrangeSubInner extends Base<String>.BaseInner<String> {} 
} 

Naturalmente, questo può essere utilizzato per rompere il tipo di invariante (cioè causa inquinamento mucchio):

StrangeSub ss = new StrangeSub(); 
    ss.e = 42; 
    String s = ss.new StrangeSubInner().e(); 

Il compilatore di eclipse accetta le specifiche del linguaggio Java come valore nominale e accetta il codice sopra riportato senza emettere un avviso "non controllato". Sebbene sia tecnicamente compatibile con il JLS, questo chiaramente viola le sue intenzioni.

The Sun Java Compiler respinge la dichiarazione di StrangeSubInner con:

Test.java:32: type parameter java.lang.String is not within its bound 
     protected class StrangeSubInner extends Base<String>.BaseInner<String> {} 
                    ^

A quanto pare il compilatore non ha semplicemente controllare il parametro di tipo contro super-parametro class tipo di interiore legato come Eclipse ha fatto. In questo caso, ritengo che sia la cosa giusta da fare, poiché la dichiarazione è chiaramente non sicura. Tuttavia, il compilatore Sun rifiuta ugualmente la seguente dichiarazione, anche se è di tipo dimostrabilmente sicura:

class StrangeSub extends Base<Integer> { 
    protected class StrangeSubInner extends BaseInner<Integer> {} 
} 

mia impressione è che verificare la coerenza di questo restrizioni di tipo a forma di diamante è oltre le capacità del compilatore Sun, e tali costrutti vengono quindi sommariamente respinti.

Per ovviare a questa limitazione, proverei prima a eliminare il parametro di tipo su CompoundIterator.

+0

Grazie, quindi ho bisogno di farlo alla vecchia maniera - appena lanciato (il generico è stato usato per un membro). –

+0

+1 Molto interessante. –

1

Forse questo non è molti progressi, ma sono riuscito a ridurre il codice precedente al seguente codice che mostra ancora lo stesso comportamento strano:

class Base<E> { 
    protected class BaseInner<I extends E>{ 
    } 
} 

class Sub<E> extends Base<E>{ 
    class SubInner extends BaseInner<E> { 
    } 
} 
Problemi correlati