JavaRush /Java-Blog /Random-DE /Klassen, Arten verschachtelter Klassen mit Beispielen
Ярослав
Level 40
Днепр

Klassen, Arten verschachtelter Klassen mit Beispielen

Veröffentlicht in der Gruppe Random-DE
Hallo zusammen. In diesem Thema möchte ich ausführlich über Java-Klassen und ihre Typen sprechen, um Anfängern das Verständnis dieses Themas zu erleichtern und vielleicht Nicht-Neulingen etwas Neues beizubringen. Wo möglich, wird alles anhand von Beispielen aus der Praxis mit begleitenden Codebeispielen gezeigt. Lass uns anfangen. Klassen, Arten verschachtelter Klassen mit Beispielen - 1Und ich möchte anmerken, dass die Hauptsache darin besteht, die ersten beiden Klassentypen zu verstehen, und dass lokale und anonyme Klassen einfach Untertypen der inneren Klasse sind.

Was ist eine Klasse?

Eine Klasse ist eine logische Beschreibung von etwas, eine Vorlage, mit der Sie echte Instanzen genau dieser Sache erstellen können. Mit anderen Worten handelt es sich lediglich um eine Beschreibung dessen, wie die erstellten Entitäten aussehen sollten: welche Eigenschaften und Methoden sie haben sollten. Eigenschaften sind Merkmale einer Entität, Methoden sind Aktionen, die sie ausführen kann. Ein gutes Beispiel für eine Klasse aus dem wirklichen Leben, das ein Verständnis dafür vermittelt, was eine Klasse ist, können Zeichnungen sein: Zeichnungen werden verwendet, um Strukturen zu beschreiben (Katapult, Schraubenzieher), aber eine Zeichnung ist kein Entwurf. So wie Ingenieure Baupläne verwenden, um Entwürfe zu erstellen, verwendet die Programmierung Klassen, um Objekte zu erstellen, die beschriebene Eigenschaften und Methoden haben.
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 diesem Beispiel haben wir eine Java-Klasse erstellt, die die Entität „Student“ beschreibt: Jeder Student hat einen Namen, eine Gruppe und ein Fachgebiet. Jetzt können wir an anderen Stellen im Programm echte Beispiele dieser Klasse erstellen. Mit anderen Worten: Wenn die Klasse Studentein Porträt dessen ist, was ein Schüler sein sollte, dann ist die erstellte Instanz der tatsächliche Schüler selbst. Ein Beispiel für das Anlegen eines neuen Schülers: new Student("Ivan", "KI-17-2", "Computer Engineering");Der Operator newsucht nach der Klasse Studentund ruft dann eine spezielle Methode (Konstruktor) dieser Klasse auf. Der Konstruktor gibt ein fertiges Klassenobjekt zurück Student– unseren lieben, hungrigen Studenten ohne Stipendium :))

Klassentypen in Java

In Java gibt es vier Arten von Klassen innerhalb einer anderen Klasse:
  1. Verschachtelte innere Klassen sind nicht statische Klassen innerhalb einer äußeren Klasse.

  2. Verschachtelte statische Klassen sind statische Klassen innerhalb einer äußeren Klasse.

  3. Lokale Java-Klassen sind Klassen innerhalb von Methoden.

  4. Anonyme Java-Klassen sind Klassen, die im laufenden Betrieb erstellt werden.

Wir werden über jeden von ihnen einzeln sprechen.

Nicht statische Klassen innerhalb einer äußeren Klasse

Zunächst möchte ich, dass Sie anhand eines realen Beispiels verstehen, was das ist, denn so ist es viel einfacher zu verstehen. Jetzt zerlegen wir ein wirklich großes Ding in kleinere Komponenten und zerlegen ein Flugzeug! Als Beispiel wird es jedoch genügen, ein wenig zu zeigen; wir werden es nicht vollständig aufschlüsseln. Um diesen Prozess zu visualisieren, verwenden wir ein Flugzeugdiagramm. Klassen, Arten verschachtelter Klassen mit Beispielen - 2 Zuerst müssen wir eine Klasse erstellen Airplane, in der wir eine kleine Beschreibung hinzufügen können: Name des Flugzeugs, Identifikationscode, Flug.
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
}
Jetzt wollen wir Flügel hinzufügen. Eine separate Klasse erstellen? Vielleicht ist dies die Logik, wenn wir ein komplexes Programm zum Entwerfen von Flugzeugen haben und eine große Anzahl abgeleiteter Klassen erstellen müssen (Klassen, die dieselbe Logik wie die übergeordnete Klasse haben, d. h. die Klasse, von der sie erben, aber Sie erweitern also die übergeordnete Klasse, indem sie Logik oder detailliertere Eigenschaften hinzufügen. Aber was wäre, wenn wir nur ein Spiel hätten, in dem wir nur ein Flugzeug hätten? Dann wäre es für uns sinnvoller, die gesamte Struktur an einem Ort (in einer Klasse) fertigzustellen. Hier kommen nicht statische verschachtelte Klassen ins Spiel. Im Wesentlichen handelt es sich hierbei um eine detailliertere Beschreibung einiger Details unserer externen Klasse. In diesem Beispiel müssen wir Flügel für ein Flugzeug erstellen – links und rechts. Lasst uns kreieren!
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
}
Also haben wir eine nicht statische verschachtelte Klasse Wing(Flügel) innerhalb einer Klasse Airplane(Flugzeug) erstellt und zwei Variablen hinzugefügt – linker Flügel und rechter Flügel. Und jeder Flügel hat seine eigenen Eigenschaften (Farbe, Modell), die wir ändern können. Auf diese Weise können Sie die Strukturen so stark besetzen, wie Sie benötigen. Und beachten Sie: Zu Beginn des Diagramms gab es ziemlich viele Teile für das Flugzeug, und tatsächlich können wir alle Teile in interne Klassen einteilen, aber ein solcher Prozess ist nicht immer ratsam. Solche Momente müssen je nach Aufgabenstellung nachgezeichnet werden. Möglicherweise benötigen Sie überhaupt keine Flügel, um das Problem zu lösen. Dann besteht keine Notwendigkeit, sie auszuführen. Es ist, als würde man eine Person in Beine, Arme, Rumpf und Kopf zerschneiden – das ist möglich, aber warum, wenn diese Klasse nur zum Speichern von Daten über Personen verwendet wird? Merkmale nicht statischer verschachtelter Java-Klassen:
  1. Sie existieren nur in Objekten. Um sie zu erstellen, benötigen Sie ein Objekt. Mit anderen Worten: Wir haben unseren Flügel als Teil eines Flugzeugs entworfen. Um einen Flügel zu schaffen, brauchen wir ein Flugzeug, sonst brauchen wir es nicht.
  2. Innerhalb einer Java-Klasse dürfen keine statischen Variablen vorhanden sein. Wenn Sie Konstanten oder andere statische Elemente benötigen, müssen Sie diese in eine äußere Klasse verschieben. Dies liegt an der engen Kopplung der nicht statischen verschachtelten Klasse mit der äußeren Klasse.
  3. Die Klasse hat vollen Zugriff auf alle privaten Felder der äußeren Klasse. Diese Funktion funktioniert auf zwei Arten.
  4. Sie können einen Verweis auf eine Instanz einer externen Klasse erhalten. Beispiel: Flugzeug. Dies ist ein Link zu einem Flugzeug, dies ist ein Link zu einem Flügel.

Statische Klassen innerhalb einer äußeren Klasse

Dieser Klassentyp unterscheidet sich nicht von einer regulären äußeren Klasse, bis auf eines: Um eine Instanz einer solchen Klasse zu erstellen, müssen Sie den gesamten Pfad von der äußeren Klasse zur gewünschten Klasse auflisten, getrennt durch einen Punkt. Beispiel: Building.Plaftorm platform = new Building.Platform(); Statische Klassen werden verwendet, um verwandte Klassen nebeneinander zu platzieren, sodass die logische Struktur einfacher zu bearbeiten ist. Beispiel: Wir können eine externe Klasse erstellen Building, in der es eine bestimmte Liste von Klassen gibt, die ein bestimmtes Gebäude darstellen.
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
}
Dieses Beispiel zeigt, wie Sie mit statischen Klassen eine logische Struktur in eine praktischere Form packen können. Wenn es sie nicht gäbe, müssten wir vier völlig unterschiedliche Klassen erstellen. Die Vorteile dieses Ansatzes:
  1. Die Anzahl der Kurse ist zurückgegangen.
  2. Alle Klassen befinden sich innerhalb ihrer übergeordneten Klasse. Wir sind in der Lage, die gesamte Hierarchie zu verfolgen, ohne jede Klasse einzeln öffnen zu müssen.
  3. Wir können auf die Building-Klasse verweisen, und die IDE fordert bereits die gesamte Liste aller Unterklassen dieser Klasse an. Dies erleichtert das Auffinden der benötigten Kurse und zeigt das Gesamtbild ganzheitlicher.
Ein Beispiel für die Erstellung einer Instanz einer verschachtelten statischen Klasse:Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); Ich möchte auch darauf hinweisen, dass diese Strategie in AWT-2D-Klassen verwendet wird, um Formen wie Line2D, Arc2D, Ellipse2D und andere zu beschreiben.

Lokale Klassen

Diese Klassen werden in anderen Methoden deklariert. Tatsächlich verfügen sie über alle Eigenschaften einer nicht statischen verschachtelten Klasse, nur ihre Instanzen können nur in einer Methode erstellt werden und die Methode kann nicht statisch sein (um sie zu erstellen, benötigen Sie eine Instanz einer externen Klasse, einen Verweis auf eine (Instanz des aufrufenden Objekts wird implizit an nicht statische Methoden übergeben, und in einer statischen Methode gibt es keine Methode für diesen Link.) Aber sie haben ihre eigenen Eigenschaften:
  1. Lokale Klassen können nur mit finalen Methodenvariablen arbeiten. Die Sache ist, dass Instanzen lokaler Klassen nach Abschluss der Methode im Heap gespeichert und die Variable gelöscht werden kann. Wenn die Variable als endgültig deklariert wird, kann der Compiler eine Kopie der Variablen für die spätere Verwendung durch das Objekt speichern. Und noch etwas: Seit 8+ Java-Versionen können Sie nicht-finale Variablen in lokalen Klassen verwenden, allerdings nur unter der Bedingung, dass sie sich nicht ändern.
  2. Lokale Klassen können nicht mit Zugriffsmodifikatoren deklariert werden.
  3. Lokale Klassen haben Zugriff auf Methodenvariablen.
Lokale Klassen sind äußerst selten zu finden, da sie die Lesbarkeit des Codes erschweren und keine Vorteile bieten, außer einem – dem Zugriff auf Methodenvariablen. Ich weiß nicht, welches Beispiel einer lokalen Klasse ihren effektiven Einsatz verdeutlichen könnte, daher zeige ich nur mein Beispiel. Nehmen wir an, wir haben eine Klasse Person(wir gehen davon aus, dass es sich um eine Person handelt) mit Eigenschaften street(Straße), house(Haus). Wir möchten ein Objekt zurückgeben, um nur auf den Standort der Person zuzugreifen. Zu diesem Zweck haben wir die AddressContainer-Schnittstelle erstellt, die eine Speicherung von Daten über den Standort einer Person impliziert.
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
}
Wie Sie sehen können, haben wir innerhalb der Methode eine Klasse erstellt, die die Speicherung des Standorts einer Person implementiert, dort konstante Variablen erstellt (so dass die Variablen nach dem Verlassen der Methode in einem Objekt gespeichert wurden) und eine Methode zum Abrufen der Adresse und implementiert Haus. Jetzt können wir dieses Objekt an anderen Stellen im Programm verwenden, um den Standort einer Person zu ermitteln. Ich verstehe, dass dieses Beispiel nicht ideal ist und es richtiger wäre, es einfach so zu machen, dass man Getter in der Klasse belässt Person. Allerdings wurde die Erstellung dieser Klasse und ihre mögliche Verwendung gezeigt, und dann liegt es an Ihnen.

Anonymer Unterricht

Unter der Haube sind anonyme Klassen nur reguläre, nicht statische verschachtelte Klassen. Ihre Besonderheit ist ihre einfache Handhabung. Sie können Ihre Klasse direkt schreiben, wenn Sie eine Instanz einer anderen Klasse erstellen.
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!");
        }
    }
}
Im Wesentlichen kombinieren wir einfach zwei Dinge an einem Ort: das Erstellen einer Instanz einer Klasse ( Animal) und das Erstellen einer Instanz ihrer inneren Erbklasse ( Tiger). Andernfalls müssen wir die Klasse separat erstellen und längere Konstrukte verwenden, um das gleiche Ergebnis zu erzielen. Der Einsatz anonymer Klassen ist in vielen Fällen gerechtfertigt, insbesondere wenn:
  • der Klassenkörper ist sehr kurz;
  • es wird nur eine Instanz der Klasse benötigt;
  • die Klasse wird an der Stelle verwendet, an der sie erstellt wurde, oder unmittelbar danach;
  • Der Klassenname ist nicht wichtig und erleichtert nicht das Verständnis des Codes.
Anonyme Klassen werden in GUIs häufig zum Erstellen von Event-Handlern verwendet. Um beispielsweise eine Schaltfläche zu erstellen und auf deren Klick zu reagieren:
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
Nach Java 8 begannen sie jedoch, Lambda-Ausdrücke zu verwenden, aber vor Version 8 wurde immer noch viel Code geschrieben, und Sie können auf solche Inschriften stoßen (und werden während Ihres Trainings in JavaRush auf sie stoßen). Analog zu Lambdas:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
Ende des Artikels Vielen Dank für Ihre Aufmerksamkeit und ich hoffe, dass Sie etwas Neues gelernt oder etwas verstanden haben, was Sie vorher nicht verstanden haben. Ich möchte auch klarstellen, dass dieser Artikel zur Kategorie „Liebe zum Detail“ gehört . Dies ist meine erste Arbeit, daher hoffe ich, dass sie jemandem nützlich war. Wenn in naher Zukunft neue Ideen kommen, werde ich versuchen, etwas anderes zu schreiben, ich habe nur eine Idee ... Viel Glück an alle und Erfolg beim Programmieren :)
Kommentare
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION