JavaRush /Java Blog /Random-IT /Classi, tipi di classi nidificate con esempi
Ярослав
Livello 40
Днепр

Classi, tipi di classi nidificate con esempi

Pubblicato nel gruppo Random-IT
Ciao a tutti. In questo argomento, voglio parlare in dettaglio delle classi Java e dei loro tipi per aiutare i principianti a comprendere questo argomento e forse i non principianti a imparare qualcosa di nuovo. Ove possibile, tutto verrà mostrato utilizzando esempi di vita reale con esempi di codice di accompagnamento. Iniziamo. Classi, tipi di classi nidificate con esempi - 1E vorrei sottolineare che la cosa principale è comprendere i primi due tipi di classi, e locale e anonimo sono semplicemente sottotipi della classe interna.

Cos'è una classe?

Una classe è una descrizione logica di qualcosa, un modello con cui puoi creare istanze reali di quella stessa cosa. In altre parole, è semplicemente una descrizione di come dovrebbero essere le entità create: quali proprietà e metodi dovrebbero avere. Le proprietà sono caratteristiche di un'entità, i metodi sono azioni che può eseguire. Un buon esempio di lezione dalla vita reale, che dà un'idea di cosa sia una classe, può essere considerato un disegno: i disegni sono usati per descrivere strutture (catapulta, cacciavite), ma un disegno non è un progetto. Proprio come gli ingegneri utilizzano i progetti per creare progetti, la programmazione utilizza le classi per creare oggetti che hanno proprietà e metodi descritti.
public class Student {
    private String name, group, specialty;

    public Student(String name, String group, String specialty) {
       this.name = name;
       this.group = group;
       this.specialty = specialty;
   }

   // getters/setters
}
In questo esempio, abbiamo creato una classe Java che descrive l'entità “studente”: ogni studente ha un nome, un gruppo e una specialità. Ora, in altri punti del programma, possiamo creare esempi reali di questa classe. In altre parole: se la classe Studentè il ritratto di quello che dovrebbe essere uno studente, allora l’istanza creata è lo studente stesso. Un esempio di creazione di un nuovo studente: new Student("Ivan", "KI-17-2", "Computer Engineering");l'operatore newcerca la classe Studente quindi chiama un metodo speciale (costruttore) di questa classe. Il costruttore restituisce un oggetto di classe già pronto Student: il nostro caro studente affamato senza borsa di studio :))

Tipi di classi in Java

In Java ci sono 4 tipi di classi all'interno di un'altra classe:
  1. Le classi interne annidate sono classi non statiche all'interno di una classe esterna.

  2. Le classi statiche annidate sono classi statiche all'interno di una classe esterna.

  3. Le classi locali Java sono classi all'interno dei metodi.

  4. Le classi Java anonime sono classi create al volo.

Parleremo di ciascuno di essi separatamente.

Classi non statiche all'interno di una classe esterna

Per prima cosa voglio che tu capisca di cosa si tratta con un esempio reale, perché rende molto più facile la comprensione. Quindi ora scomporremo una cosa davvero grande in componenti più piccoli e smonteremo un aeroplano! Tuttavia, a titolo di esempio, basterà mostrarne un po', non lo scomporremo completamente. Per visualizzare questo processo, utilizzeremo un diagramma di un aereo. Classi, tipi di classi nidificate con esempi - 2 Per prima cosa dobbiamo creare una classe Airplanein cui possiamo aggiungere una piccola descrizione: nome dell'aereo, codice identificativo, volo.
public class Airplane {
    private String name, id, flight;

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    // getters/setters
}
Ora vogliamo aggiungere le ali. Creare una classe separata? Forse questa è la logica se abbiamo un programma complesso per la progettazione di aeroplani e dove dobbiamo creare un numero enorme di classi derivate (classi che hanno la stessa logica della classe genitore, cioè la classe da cui ereditano, ma quindi estendono la classe genitore aggiungendo logica o caratteristiche più dettagliate), ma cosa succede se abbiamo solo un gioco in cui abbiamo un aereo? Allora sarà più razionale per noi completare l'intera struttura in un unico posto (in una classe). È qui che entrano in gioco le classi annidate non statiche. Essenzialmente, questa è una descrizione più dettagliata di alcuni dettagli della nostra classe esterna. In questo esempio, dobbiamo creare le ali per un aereo: sinistra e destra. Creiamo!
public class Airplane {
    private String name, id, flight;
    private Wing leftWing = new Wing("Red", "X3"), rightWing = new Wing("Blue", "X3");

    public Airplane(String name, String id, String flight) {
        this.name = name;
        this.id = id;
        this.flight = flight;
    }

    private class Wing {
        private String color, model;

        private Wing(String color, String model) {
            this.color = color;
            this.model = model;
        }

        // getters/setters
    }

    // getters/setters
}
Quindi abbiamo creato una classe nidificata non statica Wing(ala) all'interno di una classe Airplane(aereo) e abbiamo aggiunto due variabili: ala sinistra e ala destra. E ogni ala ha le sue proprietà (colore, modello) che possiamo modificare. In questo modo puoi fornire alle strutture tutto il personale di cui hai bisogno. E nota: prima nel diagramma c'erano molte parti dell'aereo e, in effetti, possiamo dividere tutte le parti in classi interne, ma questo processo non è sempre consigliabile. Tali momenti devono essere tracciati a seconda dell'attività. Potresti non aver bisogno delle ali per risolvere il problema. Quindi non è necessario farli. È come tagliare una persona in gambe, braccia, busto e testa: è possibile, ma perché se questa classe viene utilizzata solo per archiviare dati sulle persone? Caratteristiche delle classi Java nidificate non statiche:
  1. Esistono solo negli oggetti, quindi per crearli è necessario un oggetto. In altre parole: abbiamo progettato la nostra ala per essere parte di un aeroplano, quindi per creare un'ala abbiamo bisogno di un aeroplano, altrimenti non ci serve.
  2. Non possono esserci variabili statiche all'interno di una classe Java. Se hai bisogno di costanti o qualsiasi altra cosa statica, devi spostarle in una classe esterna. Ciò è dovuto allo stretto accoppiamento della classe nidificata non statica con la classe esterna.
  3. La classe ha pieno accesso a tutti i campi privati ​​della classe esterna. Questa funzionalità funziona in due modi.
  4. Puoi ottenere un riferimento a un'istanza di una classe esterna. Esempio: Airplane.questo è un collegamento ad un aeroplano, questo è un collegamento ad un'ala.

Classi statiche all'interno di una classe esterna

Questo tipo di classe non è diverso dalla normale classe esterna, tranne una cosa: per creare un'istanza di tale classe, è necessario elencare l'intero percorso dalla classe esterna a quella desiderata, separato da un punto. Ad esempio: Building.Plaftorm platform = new Building.Platform(); le classi statiche vengono utilizzate per affiancare le classi correlate in modo che sia più semplice lavorare con la struttura logica. Ad esempio: possiamo creare una classe esterna Building, dove ci sarà un elenco specifico di classi che rappresenteranno uno specifico edificio.
public abstract class Building {
    private String name, address, type;

    Building(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public static class Platform extends Building {
        public Platform(String name, String address) {
            super(name, address);
            setType("Platform");
        }

        // some additional logic
    }

    public static class House extends Building {
        public House(String name, String address) {
            super(name, address);
            setType("House");
        }

        // some additional logic
    }

    public static class Shop extends Building {
        public Shop(String name, String address) {
            super(name, address);
            setType("Shop");
        }

        // some additional logic
    }

    // getters/setters
}
Questo esempio dimostra come le classi statiche consentono di impacchettare una struttura logica in una forma più conveniente. Se non esistessero dovremmo creare 4 classi completamente diverse. I vantaggi di questo approccio:
  1. Il numero delle classi è diminuito.
  2. Tutte le classi sono all'interno della classe genitore. Siamo in grado di tracciare l'intera gerarchia senza aprire ciascuna classe separatamente.
  3. Possiamo fare riferimento alla classe Building e l'IDE richiederà già l'intero elenco di tutte le sottoclassi di questa classe. Ciò renderà più semplice trovare le lezioni di cui hai bisogno e mostrerà l'intero quadro in modo più olistico.
Un esempio di creazione di un'istanza di una classe statica annidata:Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); vorrei anche notare che questa strategia viene utilizzata nelle classi AWT 2D per descrivere forme, come Line2D, Arc2D, Ellipse2D e altre.

Classi locali

Queste classi sono dichiarate all'interno di altri metodi. Hanno infatti tutte le proprietà di una classe nidificata non statica, solo che le loro istanze possono essere create solo in un metodo, e il metodo non può essere statico (per crearle è necessaria un'istanza della classe esterna, un riferimento alla l'istanza dell'oggetto chiamante viene passata implicitamente a metodi non statici e in un metodo statico non esiste alcun metodo per questo collegamento). Ma hanno le loro caratteristiche:
  1. Le classi locali possono funzionare solo con variabili del metodo finale. Il fatto è che le istanze delle classi locali possono essere archiviate nell'heap dopo il completamento del metodo e la variabile può essere cancellata. Se la variabile viene dichiarata final, il compilatore può salvare una copia della variabile per un utilizzo successivo da parte dell'oggetto. E ancora una cosa: a partire dalle versioni 8+ di Java, puoi utilizzare variabili non finali nelle classi locali, ma solo a condizione che non cambino.
  2. Le classi locali non possono essere dichiarate con modificatori di accesso.
  3. Le classi locali hanno accesso alle variabili del metodo.
Le classi locali possono essere trovate molto raramente, poiché rendono difficile la lettura del codice e non presentano alcun vantaggio, tranne uno: l'accesso alle variabili del metodo. Non so quale esempio di classe locale si possa prendere per dimostrare il loro utilizzo efficace, quindi mostrerò semplicemente il mio esempio. Diciamo che abbiamo una classe Person(si presumerà che sia una persona) con proprietà street(strada), house(casa). Vorremmo restituire qualche oggetto per accedere solo alla posizione della persona. Per fare ciò, abbiamo creato l’interfaccia AddressContainer, che implica l’archiviazione di dati sulla posizione di una persona.
public class Person {
    private String name, street, house;

    public Person(String name, String street, String house) {
        this.name = name;
        this.street = street;
        this.house = house;
    }

    private interface AddressContainer {
        String getStreet();
        String getHouse();
    }

    public AddressContainer getAddressContainer() {
        class PersonAddressContainer implements AddressContainer {
            final String street = Person.this.street, house = Person.this.house;

            @Override
            public String getStreet() {
                return this.street;
            }

            @Override
            public String getHouse() {
                return this.house;
            }
        }

        return new PersonAddressContainer();
    }

    public static void main(String[] args) {
        Person person = new Person("Nikita", "Sholohova", "17");

        AddressContainer address = person.getAddressContainer();

        System.out.println("Address: street - " + address.getStreet() + ", house - " + address.getHouse());
    }

    // getters/setters
}
Come puoi vedere, all'interno del metodo abbiamo creato una classe che implementa la memorizzazione della posizione di una persona, abbiamo creato lì delle variabili costanti (in modo che dopo essere usciti dal metodo, le variabili fossero memorizzate in un oggetto) e implementato un metodo per ottenere l'indirizzo e casa. Ora possiamo utilizzare questo oggetto in altri punti del programma per ottenere la posizione di una persona. Capisco che questo esempio non è l'ideale e sarebbe più corretto farlo semplicemente lasciando i getter nella classe Person, però è stata mostrata la creazione di questa classe e il suo possibile utilizzo, e poi dipende da voi.

Classi anonime

Dietro le quinte, le classi anonime sono solo normali classi nidificate non statiche. La loro particolarità è la facilità d'uso. Puoi scrivere la tua classe direttamente quando crei un'istanza di un'altra classe.
public class Animal {
    public void meow() {
        System.out.println("Meow!");
    }

    public static void main(String[] args) {
        Animal anonTiger = new Animal() {
            @Override
            public void meow() {
                System.out.println("Raaar!");
            }
        };

        Animal notAnonTiger = new Animal().new Tiger();

        anonTiger.meow(); // будет выведено Raaar!
        notAnonTiger.meow(); // будет выведено Raaar!
    }

    private class Tiger extends Animal {
        @Override
        public void meow() {
            System.out.println("Raaar!");
        }
    }
}
Essenzialmente, stiamo semplicemente combinando due cose in un unico posto: creare un'istanza di una classe ( Animal) e creare un'istanza della sua classe interna erede ( Tiger). Altrimenti dobbiamo creare la classe separatamente e utilizzare costrutti più lunghi per ottenere lo stesso risultato. L'uso di classi anonime è giustificato in molti casi, in particolare quando:
  • il corpo della classe è molto breve;
  • è necessaria una sola istanza della classe;
  • la classe viene utilizzata nel luogo in cui è stata creata o immediatamente dopo;
  • Il nome della classe non è importante e non semplifica la comprensione del codice.
Le classi anonime vengono spesso utilizzate nelle GUI per creare gestori di eventi. Ad esempio, per creare un pulsante e reagire al suo clic:
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
Tuttavia, dopo Java 8 hanno iniziato a utilizzare le espressioni lambda, ma molto codice è stato scritto prima della versione 8 e potresti incontrare (e incontrerai durante la tua formazione in JavaRush) tali iscrizioni.\ Analogo con lambda:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
Fine articolo Grazie a tutti per l'attenzione e spero che abbiate imparato qualcosa di nuovo o capito qualcosa che prima non capivate. Ci tengo inoltre a precisare che questo articolo appartiene alla categoria “attenzione al dettaglio” . Questo è il mio primo lavoro, quindi spero che sia stato utile a qualcuno. Nel prossimo futuro, quando arriveranno nuove idee, proverò a scrivere qualcos'altro, ho solo un'idea... Buona fortuna a tutti e successo nella programmazione :)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION