2011-11-03 13 views
19

I.e. perché la seguente "dipendenza ciclica" non è possibile?Perché Java impedisce l'ereditarietà delle interfacce interne?

public class Something implements Behavior { 
    public interface Behavior { 
     // ... 
    } 
} 

Poiché le interfacce non fanno riferimento alla classe esterna, questo dovrebbe essere consentito; tuttavia, il compilatore mi costringe a definire tali interfacce al di fuori della classe. C'è qualche spiegazione logica per questo comportamento?

+0

Sembra che il classloader debba prima leggere la classe per conoscere l'interfaccia di cui ha bisogno per definire la classe in primo luogo ... Non conosco i dettagli del caricamento delle classi, ma sembra abbastanza ovvio. –

+2

@donneo: poiché il compilatore si lamenta di una "dipendenza ciclica", immagino che sappia già quali tipi sono definiti nella classe interna. Mi sembra una restrizione arbitraria. –

+0

@PhilipK: quale compilatore stai usando? I miei (Oracle JDK 6 e 7) si lamentano solo di "non trovare il simbolo". A parte questo: una buona domanda, dal momento che un'interfaccia annidata non si affida * * in modo tecnico alla classe esterna, questo * potrebbe * essere legale. –

risposta

11

alle corrispondenti specifiche:

http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.1.4

Una classe C dipende direttamente un tipo T se T è menzionato nella estende o implementa clausola C sia come superclasse o superinterfaccia o come qualificatore di un nome superclasse o superinterfaccia.

http://java.sun.com/docs/books/jls/third_edition/html/interfaces.html#9.1.3

Un'interfaccia I dipende direttamente su un tipo T se T è menzionato nel estende clausola che sia come superinterfaccia o come qualificazione di un nome superinterfaccia.

Pertanto se A extends|implements B.C, A dipende sia C e B. Spec quindi proibisce le dipendenze circolari.

La motivazione di includere B nella dipendenza non è chiara. Come hai detto, se il livello B.C viene promosso al primo livello C2, non molto è diverso per quanto riguarda il sistema di tipi, quindi perché A extends C2 è ok, ma non A extends B.C?Concesso un tipo nidificato B.C ha qualche accesso al contenuto di B, ma non riesco a trovare nulla nelle specifiche che rende problematico lo A extends B.C.

L'unico problema è quando C è una classe interna. Supponiamo che B=A, A extends A.C sia vietato, perché esiste una dipendenza circolare di "istanza che include". Questa è probabilmente la vera motivazione: proibire alle classi esterne di ereditare la classe interiore. Le regole attuali sono più generalizzate, perché sono più semplici e hanno comunque un senso anche per le classi non interne.

10

Immagina di essere il compilatore.

Ti stiamo dicendo di creare una classe Qualcosa. Questa classe implementa il comportamento ... Ma il comportamento non esiste ancora perché qualcosa non è già registrato ...

Capisci il problema?

Vedere la classe come casella che contiene oggetti. Il comportamento è contenuto nella scatola Qualcosa. Ma qualcosa non esiste.

+3

Questa sarebbe una risposta valida se la domanda riguardava il C++. –

+1

Sì, ma Behavior è un'interfaccia e quindi non dipende dalla creazione di Something. –

+0

Sì, perché quell'interfaccia è parte di Something. Qualcosa deve esistere prima di poter fare riferimento al comportamento, ma di creare qualcosa che deve fare riferimento al comportamento. –

0

Il semplice fatto che le specifiche della lingua lo vietino dovrebbe essere sufficiente.

Alcuni motivi mi veniva in mente:

  • Non sarebbe utile.

  • Per qualsiasi motivo si potrebbe desiderare di utilizzare questo, sono sicuro che esistono opzioni migliori.

  • Le classi figlio devono estendere le classi base, quindi perché dichiarare una classe base all'interno del proprio figlio?

  • Sarebbe controintuitivo che una classe separata estenda la tua classe interiore.

+0

Sarebbe utile per i casi in cui è necessario che l'interfaccia di callback passi a una classe diversa. – ismailarilik