Perché non possiamo avere un metodo statico in una class interna (non statica)?

Perché non possiamo avere un metodo statico in una class interiore non statica?

Se faccio in modo che la class interna sia statica, funziona. Perché ?

    Poiché un’istanza di una class interna è implicitamente associata a un’istanza della sua class esterna, non può definire alcun metodo statico. Poiché una class nidificata statica non può riferirsi direttamente alle variabili di istanza o ai metodi definiti nella sua class di inclusione, può usarli solo attraverso un riferimento a un object, è sicuro dichiarare metodi statici in una class nidificata statica.

    Non ha molto senso consentire un metodo statico in una class interna non statica; come accedervi? Non è ansible accedere (almeno inizialmente) a un’istanza di class interna non statica senza passare attraverso un’istanza di class esterna. Non esiste un modo puramente statico per creare una class interiore non statica.

    Per una class esterna Outer , puoi accedere a un metodo statico test() come questo:

     Outer.test(); 

    Per una class interna statica Inner , puoi accedere al suo metodo statico innerTest() questo modo:

     Outer.Inner.innerTest(); 

    Tuttavia, se Inner non è statico, non esiste ora un modo puramente statico per fare riferimento al metodo più innertest . Le classi interne non statiche sono legate a un’istanza specifica della loro class esterna. Una funzione è diversa da una costante, in quanto è garantito che un riferimento a Outer.Inner.CONSTANT è ambiguo in quanto una funzione chiama Outer.Inner.staticFunction(); non è. Diciamo che hai Inner.staticFunction() che chiama getState() , che è definito in Outer . Se si tenta di richiamare quella funzione statica, ora si ha un riferimento ambiguo alla class Inner. Cioè, su quale istanza della class interna invochi la funzione statica? Importa. Vedi, non c’è un modo veramente statico per fare riferimento a quel metodo statico, a causa del riferimento implicito all’object esterno.

    Paul Bellora ha ragione che i progettisti linguistici avrebbero potuto permetterselo. Dovrebbero quindi disabilitare con cura qualsiasi accesso al riferimento implicito alla class esterna nei metodi statici della class interna non statica. A questo punto, qual è il valore di questo essere una class interiore se non puoi fare riferimento alla class esterna, eccetto staticamente? E se l’accesso statico va bene, allora perché non dichiarare l’intera class interna statica? Se si rende semplicemente statica la class interna stessa, non si ha alcun riferimento implicito alla class esterna e non si ha più questa ambiguità.

    Se hai effettivamente bisogno di metodi statici su una class interna non statica, probabilmente hai bisogno di ripensare il tuo design.

    Ho una teoria, che può o non può essere corretta.

    Innanzitutto, dovresti sapere alcune cose su come le classi interne sono implementate in Java. Supponiamo che tu abbia questa class:

     class Outer { private int foo = 0; class Inner implements Runnable { public void run(){ foo++; } } public Runnable newFooIncrementer(){ return new Inner(); } } 

    Quando lo compili, il bytecode generato avrà l’aspetto di scrivere qualcosa del genere:

     class Outer { private int foo = 0; static class Inner implements Runnable { private final Outer this$0; public Inner(Outer outer){ this$0 = outer; } public void run(){ this$0.foo++; } } public Runnable newFooIncrementer(){ return new Inner(this); } } 

    Ora, se permettessimo metodi statici in classi interne non statiche, potremmo voler fare qualcosa di simile.

     class Outer { private int foo = 0; class Inner { public static void incrFoo(){ foo++; } } } 

    … che sembra abbastanza ragionevole, poiché la class Inner sembra avere una incarnazione per istanza Outer . Ma come abbiamo visto sopra, le classi interne non statiche sono in realtà solo zucchero sintattico per classi “interne” statiche, quindi l’ultimo esempio sarebbe approssimativamente equivalente a:

     class Outer { private int foo = 0; static class Inner { private final Outer this$0; public Inner(Outer outer){ this$0 = outer; } public static void incrFoo(){ this$0.foo++; } } } 

    … che chiaramente non funzionerà, poiché this$0 non è statico. Questo tipo di spiegazione spiega perché i metodi statici non sono consentiti (sebbene sia ansible rendere l’argomento che è ansible consentire i metodi statici purché non facciano riferimento all’object che li include) e perché non sia ansible avere campi statici non finali ( sarebbe contro-intuitivo se istanze di classi interne non statiche di oggetti diversi condividessero lo “stato statico”). Spiega anche perché i campi finali sono consentiti (a patto che non facciano riferimento all’object che lo racchiude).

    L’unica ragione è “non è un must”, quindi perché preoccuparsi di supportarlo?

    Sintatticamente, non vi è alcun motivo per proibire a una class interiore di avere membri statici. Sebbene un’istanza di Inner sia associata a un’istanza di Outer , è comunque ansible utilizzare Outer.Inner.myStatic per riferire un membro statico di Inner se java decide di farlo.

    Se hai bisogno di condividere qualcosa tra tutte le istanze di Inner , puoi semplicemente inserirle in Outer come membri statici. Questo non è peggiore di quello che usi i membri statici in Inner , dove Outer può comunque accedere a qualsiasi membro privato di Inner comunque (non migliora l’incapsulamento).

    Se hai bisogno di condividere qualcosa tra tutte le istanze di Inner create da un object outer , ha più senso metterle nella class Outer come membri ordinari.

    Non sono d’accordo sul fatto che “una class nidificata statica è praticamente solo una class di alto livello”. Penso che sia meglio considerare una class / class interna nidificata statica come parte della class esterna, perché possono accedere ai membri privati ​​della class esterna. E i membri della class esterna sono anche “membri della class interiore”. Quindi non è necessario supportare membri statici nella class interna. Un membro ordinario / statico nella class esterna sarà sufficiente.

    Risposta breve: il modello mentale che la maggior parte dei programmatori ha di come funziona lo scope non è il modello utilizzato da javac. Abbinare il modello più intuitivo avrebbe richiesto un grande cambiamento nel modo in cui funziona javac.

    La ragione principale per cui i membri statici nelle classi interne sono desiderabili è per la pulizia del codice: un membro statico usato solo da una class interiore dovrebbe vivere al suo interno, piuttosto che dover essere collocato nella class esterna. Prendere in considerazione:

     class Outer { int outID; class Inner { static int nextID; int id = nextID++; String getID() { return outID + ":" + id; } } } 

    Considera cosa succede in getID () quando uso l’identificatore non qualificato “outID”. L’ambito in cui appare questo identificatore assomiglia a qualcosa:

     Outer -> Inner -> getID() 

    Qui, ancora una volta perché questo è esattamente come funziona javac, il livello “Outer” dell’oscilloscopio include sia i membri statici che i membri dell’istanza di Outer. Ciò è fonte di confusione perché di solito ci viene detto di pensare alla parte statica di una class come a un altro livello dello scope:

     Outer static -> Outer instance -> instanceMethod() \----> staticMethod() 

    In questo modo di pensarci, ovviamente staticMethod () può vedere solo membri statici di Outer. Ma se questo fosse il modo in cui funziona javac, fare riferimento a una variabile di istanza in un metodo statico determinerebbe un errore “nome non risolvibile”. Quello che realmente accade è che il nome viene trovato in ambito, ma poi un ulteriore livello di controllo entra e capisce che il nome è stato dichiarato in un contesto di istanza e viene fatto riferimento da un contesto statico.

    OK, come si relaziona con le classi interne? Ingenuamente, pensiamo che non ci sia ragione per cui le classi interne non possano avere un ambito statico, perché stiamo immaginando che lo scope funzioni in questo modo:

     Outer static -> Outer instance -> Inner instance -> getID() \------ Inner static ------^ 

    In altre parole, le dichiarazioni statiche nella class interna e le dichiarazioni di istanza nella class esterna sono entrambe nell’ambito nell’ambito del contesto dell’istanza della class interna, ma nessuna di queste è effettivamente nidificata nell’altra; entrambi sono nidificati nello scope statico di Outer.

    Questo non è esattamente il modo in cui funziona javac: esiste un unico livello di ambito sia per i membri statici che per i membri di istanza e l’ambito è sempre strettamente nidificato. Anche l’ereditarietà viene implementata copiando le dichiarazioni nella sottoclass piuttosto che ramificando e cercando l’ambito della superclass.

    Per supportare i membri statici delle classi interne javac dovrebbe dividere gli ambiti statici e di istanza e supportare la ramificazione e il ricongiungimento delle gerarchie dell’ambito, oppure dovrebbe estendere la sua semplice bozza “contesto statico” per cambiare per tracciare il tipo di contesto a tutti i livelli della class nidificata nell’ambito corrente.

    Perché non possiamo avere un metodo statico in una class interiore non statica?

    Nota: una class nidificata non statica è nota come class interna, quindi non si ha non-static inner class come tale.

    Un’istanza di class interna non ha esistenza senza un’istanza corrispondente di class esterna. Una class interna non può dichiarare membri statici diversi dalle costanti di tempo di compilazione. Se fosse permesso, allora ci sarebbe stata ambiguità sul significato di static . In quel caso ci sarebbero state certe confusioni:

    1. Significa che c’è una sola istanza in VM?
    2. O solo una istanza per object esterno?

    Questo è il motivo per cui i progettisti presero la decisione di non gestire affatto questo problema.

    Se faccio in modo che la class interna sia statica, funziona. Perché ?

    Anche in questo caso non è ansible creare una class interna statica, piuttosto è ansible dichiarare una class statica come nidificata. In questo caso, questa class annidata fa effettivamente parte della class esterna e può avere membri statici senza alcun problema.

    Questo argomento ha attirato l’attenzione di molti, tuttavia cercherò di spiegare nel modo più semplice ansible.

    Innanzitutto, con riferimento a http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.1 , una class o un’interfaccia viene inizializzata immediatamente prima della prima occorrenza / invocazione di qualsiasi membro preceduto dalla parola chiave static.

    1. Quindi, se sopportiamo un membro statico all’interno di una class interna, ciò porterà all’inizializzazione della class interna, non necessariamente alla class esterna / racchiusa. Quindi, ostacoliamo la sequenza di inizializzazione della class.

    2. Considerare anche il fatto che una class interna non statica è associata all’istanza di una class chiusa / esterna. Quindi, associare un’istanza significherà che la class interna esisterà all’interno di un’istanza di class Outer e sarà diversa tra le istanze.

    Semplificando il punto, per accedere al membro statico abbiamo bisogno di un’istanza di una class Outer, dalla quale dovremo nuovamente creare un’istanza di class interna non statica. I membri statici non dovrebbero essere associati alle istanze e pertanto si riceve un errore di compilazione.

    Una class interna è qualcosa di completamente diverso da una class nidificata statica, sebbene entrambi siano simili nella syntax. Le classi nidificate statiche sono solo un mezzo per il raggruppamento, mentre le classi interne hanno una forte associazione e l’accesso a tutti i valori della loro class esterna. Dovresti essere sicuro del motivo per cui vuoi usare una class interiore e poi dovrebbe essere abbastanza naturale quale devi usare. Se hai bisogno di dichiarare un metodo statico, probabilmente è una class nidificata statica che vuoi comunque.

    supponiamo che ci siano due istanze di class esterna e che entrambe abbiano una class interna istanziata. Ora se la class interna ha un membro statico, manterrà una sola copia di quel membro nell’area di heap. In questo caso entrambi gli oggetti della class esterna faranno riferimento a questo copia singola e possono alterarlo insieme. Ciò può causare una situazione di “lettura sporca” quindi impedire che Java abbia applicato questa restrizione. Un altro punto di forza per supportare questo argomento è che java consente ai membri statici finali qui, quelli i cui valori non possono essere cambiato da entrambi gli oggetti di class esterni. Per favore, fammi sapere se ho torto.

    Prima di tutto perché qualcuno vuole definire il membro statico in una class interiore non statica? la risposta è, in modo che il membro della class esterna possa usare quel membro statico solo con il nome della class interna, giusto?

    Ma per questo caso possiamo definire direttamente il membro nella class esterna. che sarà associato a tutti gli oggetti della class interna, all’interno dell’istanza di class esterna.

    come sotto il codice,

     public class Outer { class Inner { public static void method() { } } } 

    può essere scritto in questo modo

     public class Outer { void method() { } class Inner { } } 

    Quindi, secondo me, per non complicare il codice, java designer non consente questa funzionalità o potremmo vedere questa funzionalità nelle versioni future con alcune funzionalità aggiuntive.

    Cerca di trattare la class come un campo normale, quindi capirai.

     //something must be static. Suppose something is an inner class, then it has static keyword which means it's a static class Outer.something 

    È inutile che i membri della class interiore siano statici perché in primo luogo non sarete in grado di accedervi.

    Pensa a questo, per accedere a un membro statico usi className.memberName, nel nostro caso, dovrebbe essere qualcosa come outerclassName.innerclassName.memberName ,,, ora capisci perché innerclass deve essere statico ….

    Sono consentiti metodi statici su classi nidificate statiche. Per esempio

     public class Outer { public static class Inner { public static void method() { } } }