Sobes.tech
Middle

Parla delle classi annidate e in quali casi vengono utilizzate.

sobes.tech AI

Risposta dell'AI

Le classi annidate (Nested Classes) in Java sono classi definite all’interno di un’altra classe. Si dividono in due tipi: statiche (Static Nested Classes) e interne (Inner Classes).

Classi annidate statiche

  • Sono dichiarate con il modificatore static.
  • Hanno accesso solo ai membri statici della classe esterna (anche quelli nascosti).
  • Non hanno accesso ai membri non statici della classe esterna.
  • Per creare un’istanza di una classe annidata statica, non è richiesta un’istanza della classe esterna:
    // Classe esterna
    class Outer {
        static int outerStaticField;
        int outerInstanceField;
    
        // Classe annidata statica
        static class StaticNested {
            void accessOuter() {
                // Accesso al campo statico della classe esterna
                System.out.println(Outer.outerStaticField);
                // Nessun accesso a outerInstanceField
                // System.out.println(outerInstanceField); // Errore di compilazione
            }
        }
    }
    
    // Uso della classe annidata statica
    class Main {
        public static void main(String[] args) {
            Outer.StaticNested nestedObject = new Outer.StaticNested();
            nestedObject.accessOuter();
        }
    }
    

Classi interne

  • Non sono dichiarate con il modificatore static.
  • Hanno pieno accesso a tutti i membri della classe esterna (statici e non statici, anche quelli nascosti).
  • Un’istanza della classe interna può esistere solo in presenza di un’istanza della classe esterna.
  • Per creare un’istanza della classe interna, è necessaria un’istanza della classe esterna:
    // Classe esterna
    class Outer {
        static int outerStaticField;
        int outerInstanceField;
    
        // Classe interna
        class Inner {
            void accessOuter() {
                // Accesso al campo statico della classe esterna
                System.out.println(Outer.outerStaticField);
                // Accesso al campo non statico della classe esterna
                System.out.println(outerInstanceField);
            }
        }
    }
    
    // Uso della classe interna
    class Main {
        public static void main(String[] args) {
            Outer outerObject = new Outer();
            Outer.Inner innerObject = outerObject.new Inner();
            innerObject.accessOuter();
        }
    }
    

Le classi interne si suddividono in:

  • Classi interne regolari: Sono definite direttamente all’interno del corpo della classe esterna.
  • Classi interne locali: Sono definite all’interno di metodi, costruttori o blocchi di inizializzazione. Sono visibili solo all’interno di quel blocco.
    class Outer {
        void display() {
            class LocalInner { // Classe interna locale
                void message() {
                    System.out.println("Classe interna locale");
                }
            }
            LocalInner obj = new LocalInner();
            obj.message();
        }
    }
    
  • Classi interne anonime: Sono classi senza nome, usate per creare un’istanza di una classe o interfaccia e fornire la loro implementazione immediatamente. Sono spesso usate con ascoltatori di eventi.
    interface Greeting {
        void sayHello();
    }
    
    class Main {
        public static void main(String[] args) {
            Greeting greeting = new Greeting() { // Classe anonima
                @Override
                public void sayHello() {
                    System.out.println("Ciao!");
                }
            };
            greeting.sayHello();
        }
    }
    

Quando si usano le classi annidate:

  • Gruppamento logico: Se una classe è solo una parte di un’altra classe e ha senso raggrupparle insieme. Questo migliora la leggibilità e la manutenibilità del codice.
  • Incapsulamento: Le classi annidate possono accedere ai membri della classe esterna, garantendo una relazione più stretta e la possibilità di nascondere i dettagli di implementazione.
  • Codice più leggibile: Quando una piccola classe semplice viene usata solo in un punto, annidarla può rendere il codice più ordinato.
  • Utilizzo efficiente delle risorse: Le classi interne hanno accesso ai membri della classe esterna senza doverli passare esplicitamente, semplificando il codice. Un esempio sono le implementazioni di iterator.
  • Implementazione di interfacce o estensione di classi nel contesto: Le classi interne anonime sono spesso usate per fornire un’implementazione compatta di interfacce o classi astratte "al volo".
  • Nascondere l’implementazione: Nascondere una classe all’interno di un’altra, rendendola invisibile dall’esterno.

Confronto tra classi annidate statiche e interne:

Parametro Classe annidata statica Classe interna
Modificatore static No
Accesso ai membri della classe esterna Solo statici (anche privati) Tutti i membri (statici e non statici, privati)
È necessaria un’istanza della classe esterna per crearla No
Relazione con l’istanza della classe esterna No

La scelta tra una classe annidata statica e una interna dipende dal fatto che la classe interna abbia bisogno di accedere ai membri non statici della classe esterna. Se sì, usa la classe interna. Se no, la classe annidata statica è una scelta più adatta, poiché non è legata a un’istanza della classe esterna e può essere più efficiente.