CodeGym /Java Blog /Random-IT /Classi interne nidificate
John Squirrels
Livello 41
San Francisco

Classi interne nidificate

Pubblicato nel gruppo Random-IT
CIAO! Oggi affronteremo un argomento importante: come funzionano le classi nidificate in Java. Java ti consente di creare classi all'interno di un'altra classe:

class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
Queste classi interne sono chiamate nidificate. Si dividono in 2 tipologie:
  1. Classi nidificate non statiche. Queste sono anche chiamate classi interne.
  2. Classi nidificate statiche.
A loro volta, le classi interne hanno due sottocategorie distinte. Oltre a essere semplicemente una classe interna, una classe interna può anche essere:
  • una classe locale
  • una classe anonima
Confuso? :) Va bene. Ecco un diagramma per chiarezza. Tornaci durante la lezione se improvvisamente ti trovi confuso! Classi interne nidificate - 2Nella lezione di oggi parleremo delle classi interne (note anche come classi nidificate non statiche). Sono particolarmente evidenziate nel diagramma generale in modo da non perdersi :) Cominciamo con la domanda ovvia: perché si chiamano classi "interne"? La risposta è abbastanza semplice: perché sono 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("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 Bicycleclasse. Ha 2 campi e 1 metodo: start(). Classi interne nidificate - 3Si differenzia da una classe ordinaria in quanto contiene due classi: Handlebare Seat. Il loro codice è scritto all'interno della Bicycleclasse. 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. Classi interne nidificate - 4In questa situazione, la nostra soluzione precedente non funzionerà. In un negozio di biciclette, ogni singola parte della bicicletta ha senso anche se separata da una bicicletta. Ad esempio, avremo bisogno di metodi come "vendere pedali a un cliente", "acquistare un nuovo sedile", ecc. Sarebbe un errore utilizzare classi interne qui: ogni singola parte di bicicletta nel nostro nuovo programma ha un significato che sta proprio: può essere separato dal concetto di bicicletta. Questo è esattamente ciò a cui devi prestare attenzione se ti stai chiedendo se dovresti usare classi interne o organizzare tutte le entità come classi separate. La programmazione orientata agli oggetti è utile in quanto semplifica la modellazione di entità del mondo reale. Questo può essere il tuo principio guida quando decidi se utilizzare le classi interne. In un vero negozio, i pezzi di ricambio sono separati dalle biciclette - va bene. Ciò significa che va bene anche quando si progetta un programma. Ok, abbiamo capito 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 ha senso: questo è il motivo per cui abbiamo creato le classi interne Seate Handlebarnel 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:

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

    Ad esempio, aggiungiamo una int seatPostDiametervariabile (che rappresenta il diametro del reggisella) alla nostra Bicycleclasse.

    Quindi, nella Seatclasse interna, possiamo creare un displaySeatProperties()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!

  3. 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();
    }
    
  4. 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);
           }
       }
    }
    
  5. 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, protectede package private.

    Perché è importante?

    Ciò influisce su dove possiamo creare istanze della classe interna nel nostro programma.

    Se la nostra Seatclasse è dichiarata come public, possiamo creare Seatoggetti 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 Handlebarclasse interna dalla Mainclasse.

    Se dichiariamo la classe interna come private, saremo in grado di creare oggetti solo all'interno della classe esterna.

    Non possiamo più creare un Seatoggetto "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 :)

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

    Il protectedmodificatore fornisce l'accesso a una variabile di istanza nelle sottoclassi e nelle classi che si trovano nello stesso pacchetto.

    protectedfunziona anche per le classi interne. Possiamo creare protectedoggetti 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.

Per ora è tutto :) Ma non rallentare! Le classi interne sono un argomento abbastanza vasto che continueremo ad esplorare nella prossima lezione. Ora puoi rinfrescarti la memoria della lezione del nostro corso sulle classi interne . E la prossima volta parliamo di classi nidificate statiche.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION