Perché Java proibisce i campi statici nelle classi interne?

class OuterClass { class InnerClass { static int i = 100; // compile error static void f() { } // compile error } } 

Sebbene non sia ansible accedere al campo statico con OuterClass.InnerClass.i , se voglio registrare qualcosa che dovrebbe essere statico, ad esempio il numero di oggetti InnerClass creati, sarebbe utile rendere statico quel campo. Quindi, perché Java proibisce campi / metodi statici nelle classi interne?

EDIT: So come rendere il compilatore felice con la class nested statica (o la class interna statica), ma quello che voglio sapere è perché java proibisce campi / metodi statici all’interno delle classi interne (o della class interna ordinaria) dal design della lingua e aspetti di implementazione, se qualcuno ne sa di più.

L’idea dietro le classi interne è quella di operare nel contesto dell’istanza allegata. In qualche modo, consentendo alle variabili e ai metodi statici di contraddire questa motivazione?

8.1.2 Classi interne e istanze ricorrenti

Una class interna è una class nidificata che non è dichiarata in modo esplicito o implicito statico. Le classi interne non possono dichiarare inizializzatori statici (§8.7) o interfacce membro. Le classi interne non possono dichiarare membri statici, a meno che non siano campi costanti in fase di compilazione (§15.28).

quello che voglio sapere è perché java proibisce campi / metodi statici all’interno delle classi interne

Perché quelle classi interne sono classi interne di “istanza”. Cioè, sono come un attributo di istanza dell’object che lo racchiude.

Dal momento che sono classi di “istanze”, non ha alcun senso consentire static caratteristiche static , poiché static è pensato per funzionare senza un’istanza in primo luogo.

È come se tu provassi a creare un attributo statico / di istanza allo stesso tempo.

Prendi il seguente esempio:

 class Employee { public String name; } 

Se crei due istanze di dipendente:

 Employee a = new Employee(); a.name = "Oscar"; Employee b = new Employee(); b.name = "jcyang"; 

È chiaro perché ognuno ha il proprio valore per il name della proprietà, giusto?

Lo stesso accade con la class interiore; ogni istanza di class interna è indipendente dall’altra istanza di class interna.

Pertanto, se si tenta di creare un attributo di class counter , non è ansible condividerlo con due istanze diverse.

 class Employee { public String name; class InnerData { static count; // ??? count of which ? a or b? } } 

Quando crei l’istanza a e b nell’esempio sopra, quale sarebbe il valore corretto per il count variabili statiche? Non è ansible determinarlo, perché l’esistenza della class InnerData dipende completamente da ciascuno degli oggetti che lo racchiudono.

Ecco perché, quando la class viene dichiarata static , non ha più bisogno di un’istanza vivente per vivere da sola. Ora che non esiste alcuna dipendenza, puoi dichiarare liberamente un attributo statico.

Penso che suoni reiterativo, ma se pensi alle differenze tra istanze e attributi di class, avrà senso.

InnerClass non può avere membri static perché appartiene a un’istanza (di OuterClass ). Se dichiari che InnerClass static per staccarlo InnerClass , il tuo codice verrà compilato.

 class OuterClass { static class InnerClass { static int i = 100; // no compile error static void f() { } // no compile error } } 

BTW: sarai ancora in grado di creare istanze di InnerClass . static in questo contesto consente che ciò avvenga senza un’istanza di OuterClass .

In realtà, puoi dichiarare campi statici se sono costanti e scritti in tempo di compilazione.

 class OuterClass { void foo() { class Inner{ static final int a = 5; // fine static final String s = "hello"; // fine static final Object o = new Object(); // compile error, because cannot be written during compilation } } } 

Ecco la motivazione che trovo più adatta a questo “limite”: è ansible implementare il comportamento di un campo statico di una class interna come campo di istanza dell’object esterno; Quindi non hai bisogno di campi / metodi statici . Il comportamento intendo è che tutte le istanze di classi interne di alcuni oggetti condividono un campo (o un metodo).

Quindi, supponendo di voler contare tutte le istanze interne della class, dovresti fare:

 public class Outer{ int nofInner; //this will count the inner class //instances of this (Outer)object //(you know, they "belong" to an object) static int totalNofInner; //this will count all //inner class instances of all Outer objects class Inner { public Inner(){ nofInner++; totalNofInner++; } } } 
  1. class La sequenza di inizializzazione è una ragione critica.

Poiché le classi interne dipendono dall’istanza della class enclose / Outer, quindi la class Outer deve essere inizializzata prima dell’inizializzazione della class Inner.
Questo è JLS dice sull’inizializzazione della class. Il punto che ci serve è che la class T verrà inizializzata se

  • Viene utilizzato un campo statico dichiarato da T e il campo non è una variabile costante.

Quindi se la class interna ha un accesso statico al campo che causerà l’inizializzazione della class interna, ma ciò non garantirà l’inizializzazione della class di inclusione.

  1. Violarebbe alcune regole di base . puoi saltare all’ultima sezione (in two cases ) per evitare cose da noob

Una cosa riguarda static nested class static nested , quando una nested class è static si comporterà proprio come una class normale in ogni modo ed è associata alla class Outer.

Ma il concetto di Inner class / Inner class nested class non-static sarà associato instance della class outer / enclosing. Si prega di notare associato ad esempio non alla class. Ora associare con istanza significa chiaramente che ( dal concetto di variabile di istanza ) esisterà all’interno di un’istanza e sarà diverso tra le istanze.

Ora, quando creiamo qualcosa di statico, ci aspettiamo che venga inizializzato quando la class viene caricata e deve essere condivisa tra tutte le istanze. Ma per essere non statici, anche le stesse classi interne stesse ( si può sicuramente dimenticare l’istanza della class interna per ora ) non sono condivise con tutte le istanze della class outer / enclosing ( almeno concettualmente ), allora come possiamo aspettarci che alcune variabili della class interiore sarà condivisa tra tutte le istanze della class interiore.

Quindi, se Java ci consente di utilizzare la variabile statica all’interno della class nidificata non statica. ci saranno due casi .

  • Se è condiviso con tutte le istanze della class interna, violerà il concetto di context of instance (variabile d’istanza). Allora è un NO.
  • Se non è condiviso con tutte le istanze, violerà il concetto di essere statico. Di nuovo NO.

In parole semplici, le classi interne non statiche sono variabili di istanza per la class esterna e vengono create solo quando viene creata una class esterna e viene creato un object di class esterna in fase di esecuzione mentre le variabili statiche vengono create in fase di caricamento della class. Quindi la class interna non statica è la cosa di runtime, ecco perché non è statica la parte di una class interiore non statica.

NOTA: considera le classi interne sempre come una variabile per una class esterna esse possono essere statiche o non statiche come qualsiasi altra variabile.

Immagino sia per coerenza. Anche se non sembra esserci alcuna limitazione tecnica, non sarà ansible accedere ai membri statici della class interna dall’esterno, ad esempio OuterClass.InnerClass.i perché il passaggio intermedio non è statico.