class OuterClass {
...
static class StaticNestedClass {
...
}
class InnerClass {
...
}
}
Queste classi interne sono chiamate nidificate. Si dividono in 2 tipologie:
- Classi nidificate non statiche. Queste sono anche chiamate classi interne.
- Classi nidificate statiche.
- una classe locale
- una classe anonima

public class Bicycle {
private String model;
private int weight;
public Bicycle(String model, int weight) {
this.model = model;
this.weight = weight;
}
public void start() {
System.out.println("Let's go!");
}
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left!");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
}
Qui abbiamo la Bicycle
classe. Ha 2 campi e 1 metodo: start()
. 
Handlebar
e Seat
. Il loro codice è scritto all'interno della Bicycle
classe. Queste sono classi a tutti gli effetti: come puoi vedere, ognuna di esse ha i suoi metodi. A questo punto, potresti avere una domanda: perché nel mondo dovremmo mettere una classe dentro un'altra? Perché farle classi interne? Bene, supponiamo di aver bisogno di classi separate per i concetti di manubrio e sedile nel nostro programma. Certo, non è necessario che li annidiamo! Possiamo fare classi ordinarie. Ad esempio, in questo modo:
public class Handlebar {
public void right() {
System.out.println("Steer right!");
}
public void left() {
System.out.println("Steer left");
}
}
public class Seat {
public void up() {
System.out.println("Seat up!");
}
public void down() {
System.out.println("Seat down!");
}
}
Ottima domanda! Naturalmente, non siamo limitati dalla tecnologia. Farlo è certamente un'opzione. Qui, la cosa importante è più la corretta progettazione delle classi dal punto di vista di un programma specifico e del suo scopo. Le classi interne servono a separare un'entità che è inestricabilmente connessa a un'altra entità. Manubrio, sedili e pedali sono componenti di una bicicletta. Separati dalla bicicletta, non hanno molto senso. Se avessimo reso tutti questi concetti classi pubbliche separate, avremmo avuto il codice come questo nel nostro programma:
public class Main {
public static void main(String[] args) {
Handlebar handlebar = new Handlebar();
handlebar.right();
}
}
Hmm... Il significato di questo codice è persino difficile da spiegare. Abbiamo qualche manubrio vago (perché è necessario? Non ne ho idea, a dire il vero). E questa maniglia gira a destra... da sola, senza bicicletta... per qualche motivo. Separando il concetto di manubrio da quello di bicicletta, abbiamo perso un po' di logica nel nostro programma. Utilizzando una classe interna, il codice appare molto diverso:
public class Main {
public static void main(String[] args) {
Bicycle peugeot = new Bicycle("Peugeot", 120);
Bicycle.Handlebar handlebar = peugeot.new Handlebar();
Bicycle.Seat seat = peugeot.new Seat();
seat.up();
peugeot.start();
handlebar.left();
handlebar.right();
}
}
Uscita console:
Seat up!
Let's go!
Steer left!
Steer right!
Ora quello che vediamo improvvisamente ha un senso! :) Abbiamo creato un oggetto bicicletta. Abbiamo creato due "sottooggetti" per biciclette: un manubrio e un sedile. Abbiamo alzato il sedile per comodità e siamo partiti: pedalare e sterzare secondo necessità! :) I metodi di cui abbiamo bisogno sono chiamati sugli oggetti appropriati. È tutto semplice e conveniente. In questo esempio, la separazione del manubrio e del sedile migliora l'incapsulamento (nascondiamo i dati sulle parti della bicicletta all'interno della classe pertinente) e ci consente di creare un'astrazione più dettagliata. Ora diamo un'occhiata a una situazione diversa. Supponiamo di voler creare un programma che simuli un negozio di biciclette e ricambi per biciclette. 
-
Un oggetto di una classe interna non può esistere senza un oggetto di una classe esterna.
Questo ha senso: questo è il motivo per cui abbiamo creato le classi interne
Seat
eHandlebar
nel nostro programma, in modo da non ritrovarci con manubri e sedili orfani.Questo codice non compila:
public static void main(String[] args) { Handlebar handlebar = new Handlebar(); }
Ne consegue un'altra caratteristica importante:
-
Un oggetto di una classe interna ha accesso alle variabili della classe esterna.
Ad esempio, aggiungiamo una
int seatPostDiameter
variabile (che rappresenta il diametro del reggisella) alla nostraBicycle
classe.Quindi, nella
Seat
classe interna, possiamo creare undisplaySeatProperties()
metodo che visualizzi le proprietà del sedile:public class Bicycle { private String model; private int weight; private int seatPostDiameter; public Bicycle(String model, int weight, int seatPostDiameter) { this.model = model; this.weight = weight; this.seatPostDiameter = seatPostDiameter; } public void start() { System.out.println("Let's go!"); } public class Seat { public void up() { System.out.println("Seat up!"); } public void down() { System.out.println("Seat down!"); } public void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
E ora possiamo visualizzare queste informazioni nel nostro programma:
public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); Bicycle.Seat seat = bicycle.new Seat(); seat.displaySeatProperties(); } }
Uscita console:
Seat properties: seatpost diameter = 40
Nota:la nuova variabile viene dichiarata con il modificatore di accesso più rigoroso (
private
). E ancora la classe interna ha accesso! -
Un oggetto di una classe interna non può essere creato in un metodo statico di una classe esterna.
Ciò è spiegato dalle caratteristiche specifiche di come sono organizzate le classi interne. Una classe interna può avere costruttori con parametri o solo il costruttore predefinito. Ma a prescindere, quando creiamo un oggetto di una classe interna, un riferimento all'oggetto della classe esterna viene passato invisibilmente all'oggetto creato della classe interna. Dopotutto, la presenza di un tale riferimento all'oggetto è un requisito assoluto. Altrimenti, non saremo in grado di creare oggetti della classe interna.
Ma se un metodo della classe esterna è statico, allora potremmo non avere un oggetto della classe esterna! E questa sarebbe una violazione della logica di come funziona una classe interna. In questa situazione, il compilatore genererà un errore:
public static Seat createSeat() { // Bicycle.this cannot be referenced from a static context return new Seat(); }
-
Una classe interna non può contenere variabili e metodi statici.
La logica è la stessa: metodi e variabili statici possono esistere ed essere chiamati o referenziati anche in assenza di un oggetto.
Ma senza un oggetto della classe esterna, non avremo accesso alla classe interna.
Una chiara contraddizione! Questo è il motivo per cui variabili e metodi statici non sono consentiti nelle classi interne.
Il compilatore genererà un errore se provi a crearli:
public class Bicycle { private int weight; public class Seat { // An inner class cannot have static declarations public static void displaySeatProperties() { System.out.println("Seat properties: seatpost diameter = " + Bicycle.this.seatPostDiameter); } } }
-
Quando si crea un oggetto di una classe interna, il suo modificatore di accesso è importante.
Una classe interna può essere contrassegnata con i modificatori di accesso standard:
public
,private
,protected
epackage private
.Perché è importante?
Ciò influisce su dove possiamo creare istanze della classe interna nel nostro programma.
Se la nostra
Seat
classe è dichiarata comepublic
, possiamo creareSeat
oggetti in qualsiasi altra classe. L'unico requisito è che deve esistere anche un oggetto della classe esterna.A proposito, l'abbiamo già fatto qui:
public class Main { public static void main(String[] args) { Bicycle peugeot = new Bicycle("Peugeot", 120); Bicycle.Handlebar handlebar = peugeot.new Handlebar(); Bicycle.Seat seat = peugeot.new Seat(); seat.up(); peugeot.start(); handlebar.left(); handlebar.right(); } }
Abbiamo facilmente ottenuto l'accesso alla
Handlebar
classe interna dallaMain
classe.Se dichiariamo la classe interna come
private
, saremo in grado di creare oggetti solo all'interno della classe esterna.Non possiamo più creare un
Seat
oggetto "all'esterno":private class Seat { // Methods } public class Main { public static void main(String[] args) { Bicycle bicycle = new Bicycle("Peugeot", 120, 40); // Bicycle.Seat has private access in Bicycle Bicycle.Seat seat = bicycle.new Seat(); } }
Probabilmente hai già capito la logica :)
-
I modificatori di accesso per le classi interne funzionano allo stesso modo delle variabili ordinarie.
Il
protected
modificatore fornisce l'accesso a una variabile di istanza nelle sottoclassi e nelle classi che si trovano nello stesso pacchetto.protected
funziona anche per le classi interne. Possiamo creareprotected
oggetti della classe interna:- nella classe esterna;
- nelle sue sottoclassi;
- nelle classi che si trovano nello stesso pacchetto.
Se la classe interna non ha un modificatore di accesso (
package private
), è possibile creare oggetti della classe interna:- nella classe esterna;
- nelle classi che si trovano nello stesso pacchetto.
Conosci i modificatori da molto tempo, quindi nessun problema qui.
GO TO FULL VERSION