JavaRush /Java Blog /Random-IT /Classi interne nidificate o classe interna in Java

Classi interne nidificate o classe interna in Java

Pubblicato nel gruppo Random-IT
Ciao! Oggi inizieremo a considerare un argomento importante: come funzionano le classi nidificate in Java. In inglese si chiamano classi nidificate. Java permette di creare alcune classi all'interno di altre:
class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
Sono queste classi che vengono chiamate nidificate. Si dividono in 2 tipologie:
  1. Classi nidificate non statiche - classi nidificate non statiche. Sono anche chiamate classi interne in un altro modo.
  2. Classi nidificate statiche - classi nidificate statiche.
A loro volta, le classi interne hanno due sottotipi speciali. Oltre al fatto che una classe interna può essere semplicemente una classe interna, può anche essere:
  • classe locale
  • classe anonima
Un po 'difficile? :) Va bene, ecco un diagramma per chiarezza. Ritorna su questo argomento durante la lezione se all'improvviso ti senti confuso! Classi interne nidificate - 2Nella lezione di oggi parleremo di Inner class - classi interne (sono anche classi nidificate non statiche, classi nidificate non statiche). Sono appositamente evidenziati nel diagramma generale in modo da non perdervi :) Cominciamo con la domanda ovvia: perché queste classi si chiamano “interne”? La risposta è abbastanza semplice: perché vengono creati all'interno di altre classi. Ecco un esempio:
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("Go!");
   }

   public class HandleBar {

       public void right() {
           System.out.println("Steering wheel to the right!");
       }

       public void left() {

           System.out.println("Steering wheel to the left!");
       }
   }

   public class Seat {

       public void up() {

           System.out.println("The seat is up!");
       }

       public void down() {

           System.out.println("The seat is down!");
       }
   }
}
Qui abbiamo una lezione Bicycle: bicicletta. Ha 2 campi e 1 metodo - start(). Classi interne nidificate - 3La sua differenza rispetto alla classe normale è che ha due classi, il cui codice è scritto all'interno Bicycle: queste sono le classi HandleBar(volante) e Seat(sedile). Queste sono classi a tutti gli effetti: come puoi vedere, ognuna di esse ha i propri metodi. A questo punto potresti avere una domanda: perché abbiamo inserito una classe dentro un’altra? Perché renderli interni? Ok, diciamo che nel programma abbiamo bisogno di classi separate per il volante e il sedile. Ma non devi annidarli! Puoi fare lezioni regolari. Ad esempio, in questo modo:
public class HandleBar {
   public void right() {
       System.out.println("Steering wheel to the right!");
   }

   public void left() {

       System.out.println("Steering wheel left");
   }
}

public class Seat {

   public void up() {

       System.out.println("The seat is up!");
   }

   public void down() {

       System.out.println("The seat is down!");
   }
}
Ottima domanda! Naturalmente non abbiamo limitazioni tecniche: possiamo farlo in questo modo. Si tratta più di progettare correttamente le classi dal punto di vista di un particolare programma e nel significato di quel programma. Le classi interne sono classi per evidenziare una determinata entità in un programma che è indissolubilmente legata a un'altra entità. Volante, sedile, pedali sono i componenti di una bicicletta. Separati dalla bicicletta non hanno senso. Se rendessimo tutte queste classi classi pubbliche separate, il nostro programma potrebbe avere, ad esempio, il seguente codice:
public class Main {

   public static void main(String[] args) {
       HandleBar handleBar = new HandleBar();
       handleBar.right();
   }
}
Uhm... Il significato di questo codice è perfino difficile da spiegare. Abbiamo una specie di strano manubrio per bicicletta (perché è necessario? Non ne ho idea, a dire il vero). E questo volante gira a destra... da solo, senza bicicletta... per qualche motivo. Separando l'essenza del volante dall'essenza della bicicletta, abbiamo perso la logica del nostro programma. Utilizzando una classe interna, il codice appare completamente 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:

Сиденье поднято выше!
Поехали!
Руль влево!
Руль вправо!
Ciò che stava accadendo improvvisamente aveva senso! :) Abbiamo creato un oggetto bicicletta. Abbiamo creato due dei suoi “sottooggetti”: il volante e il sedile. Abbiamo alzato il sedile più in alto per comodità e siamo partiti: rotoliamo e sterziamo dove dobbiamo andare! :) I metodi di cui abbiamo bisogno vengono chiamati sugli oggetti necessari. Tutto è semplice e conveniente. In questo esempio, evidenziare il manubrio e il sedile migliora l'incapsulamento (stiamo nascondendo i dati sulle parti della bicicletta all'interno della classe corrispondente) e ci consente di creare un'astrazione più dettagliata. Ora diamo un'occhiata ad un'altra situazione. Diciamo che vogliamo creare un programma che modelli un negozio di biciclette e ricambi. Classi interne nidificate - 4In questa situazione, la nostra soluzione precedente fallirà. All'interno dei confini di un negozio di ricambi, ogni singola parte di una bicicletta ha un significato anche indipendentemente dall'essenza della bicicletta. Ad esempio, avremo bisogno di metodi come “vendere pedali a un acquirente”, “acquistare un nuovo sedile”, ecc. Sarebbe un errore utilizzare qui classi interne: ogni singola parte della bicicletta all'interno del nostro nuovo programma ha il suo significato: è separata dall'essenza della bicicletta e non è in alcun modo collegata ad essa. Questo è ciò a cui dovresti prestare attenzione se ti stai chiedendo se è necessario utilizzare classi interne o separare tutte le entità in classi separate. La programmazione orientata agli oggetti è eccezionale perché semplifica la modellazione di entità del mondo reale. Questo è ciò che puoi usare come guida quando decidi se utilizzare le classi interne. In un vero negozio, le parti sono separate dalle biciclette: questo è normale. Ciò significa che questo sarà corretto durante la progettazione di un programma. Ok, abbiamo risolto la "filosofia" :) Ora conosciamo le importanti caratteristiche "tecniche" delle classi interne. Ecco cosa devi assolutamente ricordare e capire:
  1. Un oggetto di una classe interna non può esistere senza un oggetto di una classe “esterna”.

    Questo è logico: ecco perché abbiamo creato classi Seatinterne HandleBar, in modo che volanti e sedili senza proprietario non comparissero qua e là nel nostro programma.

    Questo codice non verrà compilato:

    public static void main(String[] args) {
    
       HandleBar handleBar = new HandleBar();
    }

    Da ciò consegue la seguente importante caratteristica:

  2. Un oggetto di una classe interna ha accesso alle variabili della classe "esterna".

    Ad esempio, aggiungiamo Bicycleuna variabile alla nostra classe int seatPostDiameter: il diametro del reggisella.

    Quindi nella classe interna Seatpossiamo creare un metodo getSeatParam()che ci dirà il parametro 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("Go!");
       }
    
       public class Seat {
    
           public void up() {
    
               System.out.println("The seat is up!");
           }
    
           public void down() {
    
               System.out.println("The seat is down!");
           }
    
           public void getSeatParam() {
    
               System.out.println("Seat parameter: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }

    E ora possiamo ottenere 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.getSeatParam();
       }
    }

    Uscita console:

    
    Параметр сиденья: диаметр подседельного штыря = 40

    Fai attenzione:la nuova variabile viene dichiarata con il modificatore più rigoroso - private. E la classe interiore ha ancora accesso!

  3. Non è possibile creare un oggetto di classe interna in un metodo statico di una classe "esterna".

    Ciò è spiegato dalle caratteristiche di progettazione delle classi interne. Una classe interna può avere costruttori con parametri o solo un costruttore predefinito. Ma indipendentemente da ciò, quando creiamo un oggetto della classe interna, al suo interno viene silenziosamente passato un riferimento a un oggetto della classe “esterna”. Dopotutto, la presenza di un tale oggetto è un prerequisito. Altrimenti non saremo in grado di creare oggetti della classe interna.

    Ma se il metodo della classe esterna è statico, allora l'oggetto della classe esterna potrebbe non esistere affatto! Ciò significa che la logica della classe interna verrà infranta. In una situazione del genere, il compilatore genererà un errore:

    public static Seat createSeat() {
    
       //Bicycle.this cannot be referenced from a static context
       return new Seat();
    }
  4. Una classe interna non può contenere variabili e metodi statici.

    La logica qui è la stessa: metodi e variabili statici possono esistere ed essere chiamati anche se non esiste alcun oggetto.

    Ma senza un oggetto della classe “esterna”, non avremo accesso alla classe interna.

    Una contraddizione evidente! Pertanto è vietata la presenza di variabili e metodi statici nelle classi interne.

    Il compilatore genererà un errore durante il tentativo di crearli:

    public class Bicycle {
    
       private int weight;
    
    
       public class Seat {
    
           //inner class cannot have static declarations
           public static void getSeatParam() {
    
               System.out.println("Seat parameter: seatpost diameter = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
  5. Quando si crea un oggetto di una classe interna, il suo modificatore di accesso gioca un ruolo importante.

    Una classe interna può essere denotata dai modificatori di accesso standard - public, e .privateprotectedpackage private

    Perché è importante?

    Ciò influisce su dove nel nostro programma possiamo istanziare la classe interna.

    Se la nostra classe Seatè dichiarata come public, possiamo creare i suoi oggetti in qualsiasi altra classe. L'unico requisito è che esista anche un oggetto della classe “esterna”.

    A proposito, lo 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 accesso alla classe interna HandleBardal file Main.

    Se dichiariamo la classe interna come private, avremo accesso solo alla creazione di oggetti all'interno della classe “esterna”.

    SeatNon saremo più in grado di creare un oggetto dall'esterno:

    private class Seat {
    
       //methods
    }
    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
    
           //Bicycle.Seat has a private access in 'Bicycle'
           Bicycle.Seat seat = bicycle.new Seat();
       }
    }

    Probabilmente hai già capito la logica :)

  6. I modificatori di accesso per le classi interne funzionano allo stesso modo delle variabili regolari.

    Il modificatore protectedfornisce l'accesso a una variabile di classe nelle sue classi discendenti e nelle classi che si trovano nello stesso pacchetto.

    Lo stesso protectedvale per le classi interne. È possibile creare oggetti protecteddi classe interna :

    • all'interno della classe "esterna";
    • nelle sue classi discendenti;
    • in quelle 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

    • all'interno della classe "esterna";
    • nelle classi che si trovano nello stesso pacchetto.

    Conosci i modificatori da molto tempo, quindi non ci saranno problemi qui.

Per ora è tutto :) Ma non rilassarti! Le classi nidificate interne sono un argomento abbastanza ampio che continueremo a esplorare nelle lezioni future. Ora puoi rispolverare la lezione sulle lezioni interne del nostro corso. E la prossima volta parleremo di classi nidificate statiche.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION