JavaRush /Blog Java /Random-PL /Klasy, rodzaje klas zagnieżdżonych z przykładami
Ярослав
Poziom 40
Днепр

Klasy, rodzaje klas zagnieżdżonych z przykładami

Opublikowano w grupie Random-PL
Cześć wszystkim. W tym temacie chcę szczegółowo omówić klasy Java i ich typy, aby pomóc początkującym zrozumieć ten temat, a być może nie-nowicjuszom nauczyć się czegoś nowego. Tam, gdzie to możliwe, wszystko zostanie pokazane na przykładach z życia wziętych z towarzyszącymi przykładami kodu. Zacznijmy. Klasy, rodzaje klas zagnieżdżonych z przykładami - 1I chciałbym zauważyć, że najważniejsze jest zrozumienie dwóch pierwszych typów klas, a lokalne i anonimowe to po prostu podtypy klasy wewnętrznej.

Co to jest klasa?

Klasa to logiczny opis czegoś, szablon, za pomocą którego można stworzyć rzeczywiste instancje tej właśnie rzeczy. Inaczej mówiąc, jest to po prostu opis tego, jak powinny wyglądać tworzone byty: jakie powinny posiadać właściwości i metody. Właściwości to cechy jednostki, metody to działania, które może ona wykonać. Dobrym przykładem klasy z życia codziennego, który pozwala zrozumieć, czym jest klasa, można uznać rysunki: rysunki służą do opisu konstrukcji (katapulta, śrubokręt), ale rysunek nie jest projektem. Tak jak inżynierowie używają planów do tworzenia projektów, programowanie używa klas do tworzenia obiektów, które mają opisane właściwości i metody.
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
}
W tym przykładzie stworzyliśmy klasę Java, która opisuje jednostkę „student”: każdy uczeń ma imię, grupę i specjalizację. Teraz w innych miejscach programu możemy stworzyć prawdziwe przykłady tej klasy. Innymi słowy: jeśli klasa Studentjest portretem tego, jaki powinien być uczeń, wówczas utworzona instancja jest rzeczywistym uczniem. Przykład utworzenia nowego ucznia: new Student("Ivan", "KI-17-2", "Computer Engineering");Operator newwyszukuje klasę Student, a następnie wywołuje specjalną metodę (konstruktor) tej klasy. Konstruktor zwraca gotowy obiekt zajęć Student- nasz drogi, głodny student bez stypendium :))

Rodzaje klas w Javie

W Javie istnieją 4 rodzaje klas wewnątrz innej klasy:
  1. Zagnieżdżone klasy wewnętrzne są klasami niestatycznymi wewnątrz klasy zewnętrznej.

  2. Zagnieżdżone klasy statyczne to klasy statyczne wewnątrz klasy zewnętrznej.

  3. Klasy lokalne Java są klasami wewnątrz metod.

  4. Anonimowe klasy Java to klasy tworzone na bieżąco.

O każdym z nich porozmawiamy osobno.

Klasy niestatyczne wewnątrz klasy zewnętrznej

Najpierw chcę, żebyście zrozumieli, o co chodzi, na prawdziwym przykładzie, bo to znacznie ułatwia zrozumienie. Zatem teraz rozłożymy naprawdę dużą rzecz na mniejsze elementy i rozmontujemy samolot! Jednak dla przykładu wystarczy trochę pokazać, nie będziemy tego rozbijać do końca. Aby zwizualizować ten proces, posłużymy się schematem samolotu. Klasy, rodzaje klas zagnieżdżonych z przykładami - 2 Najpierw musimy stworzyć klasę Airplane, do której możemy dodać krótki opis: nazwę samolotu, kod identyfikacyjny, lot.
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
}
Teraz chcemy dodać skrzydła. Utworzyć osobną klasę? Być może taka jest logika, jeśli mamy złożony program do projektowania samolotów i gdzie musimy utworzyć ogromną liczbę klas pochodnych (klas, które mają tę samą logikę co klasa nadrzędna, czyli klasa, z której dziedziczą, ale więc rozszerzają klasę nadrzędną, dodając logikę lub bardziej szczegółowe cechy), ale co, jeśli mamy tylko grę, w której mamy jedną płaszczyznę? Wtedy bardziej racjonalnie będzie dla nas skompletować całą konstrukcję w jednym miejscu (w jednej klasie). Tutaj właśnie wchodzą w grę niestatyczne klasy zagnieżdżone. Zasadniczo jest to bardziej szczegółowy opis niektórych szczegółów naszej klasy zewnętrznej. W tym przykładzie musimy stworzyć skrzydła samolotu - lewe i prawe. Stwórzmy!
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
}
Stworzyliśmy więc niestatyczną klasę zagnieżdżoną Wing(skrzydło) wewnątrz klasy Airplane(samolot) i dodaliśmy dwie zmienne – lewe skrzydło i prawe skrzydło. A każde skrzydło ma swoje właściwości (kolor, model), które możemy zmieniać. W ten sposób możesz obsadzić struktury tyle, ile potrzebujesz. I uwaga: wcześniej na schemacie było dość dużo części do samolotu i tak naprawdę wszystkie części możemy podzielić na wewnętrzne klasy, ale taki proces nie zawsze jest wskazany. Takie momenty należy prześledzić w zależności od zadania. Do rozwiązania problemu możesz w ogóle nie potrzebować skrzydeł. Wtedy nie ma potrzeby ich robić. To jakby rozciąć człowieka na nogi, ręce, tułów i głowę – jest to możliwe, ale po co, jeśli ta klasa służy tylko do przechowywania danych o ludziach? Cechy niestatycznych zagnieżdżonych klas Java:
  1. Istnieją tylko w obiektach, więc aby je stworzyć, potrzebny jest obiekt. Innymi słowy: zaprojektowaliśmy nasze skrzydło tak, aby było częścią samolotu, więc aby stworzyć skrzydło, potrzebujemy samolotu, w przeciwnym razie nie będziemy go potrzebować.
  2. Wewnątrz klasy Java nie mogą znajdować się zmienne statyczne. Jeśli potrzebujesz stałych lub czegokolwiek innego statycznego, musisz przenieść je do klasy zewnętrznej. Dzieje się tak ze względu na ścisłe powiązanie niestatycznej klasy zagnieżdżonej z klasą zewnętrzną.
  3. Klasa ma pełny dostęp do wszystkich prywatnych pól klasy zewnętrznej. Ta funkcja działa na dwa sposoby.
  4. Możesz uzyskać odwołanie do instancji klasy zewnętrznej. Przykład: Samolot. to jest połączenie z samolotem, to jest połączenie ze skrzydłem.

Klasy statyczne wewnątrz klasy zewnętrznej

Ten typ klasy nie różni się niczym od zwykłej klasy zewnętrznej, z wyjątkiem jednej rzeczy: aby utworzyć instancję takiej klasy, należy podać całą ścieżkę od klasy zewnętrznej do żądanej, oddzieloną kropką. Na przykład: Building.Plaftorm platform = new Building.Platform(); Klasy statyczne służą do umieszczania powiązanych klas obok siebie, dzięki czemu łatwiej jest pracować ze strukturą logiczną. Przykładowo: możemy stworzyć klasę zewnętrzną Building, w której znajdować się będzie konkretna lista klas, które będą reprezentowały konkretny budynek.
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
}
Ten przykład pokazuje, jak klasy statyczne pozwalają spakować strukturę logiczną w wygodniejszą formę. Gdyby ich nie było, musielibyśmy stworzyć 4 zupełnie różne klasy. Zalety tego podejścia:
  1. Zmniejszyła się liczba zajęć.
  2. Wszystkie klasy znajdują się wewnątrz swoich klas nadrzędnych. Jesteśmy w stanie prześledzić całą hierarchię bez otwierania każdej klasy z osobna.
  3. Możemy odwołać się do klasy Building, a IDE wyświetli już całą listę wszystkich podklas tej klasy. Ułatwi to znalezienie potrzebnych zajęć i pokaże cały obraz bardziej całościowo.
Przykład utworzenia instancji zagnieżdżonej klasy statycznej:Building.Shop myShop = new Building.Shop(“Food & Fun!”, “Kalyaeva 8/53”); Chciałbym również zauważyć, że strategia ta jest stosowana w klasach AWT 2D do opisu kształtów, takich jak Line2D, Arc2D, Ellipse2D i inne.

Zajęcia lokalne

Klasy te są deklarowane wewnątrz innych metod. Tak naprawdę mają one wszystkie właściwości niestatycznej klasy zagnieżdżonej, tyle że ich instancje można tworzyć tylko w metodzie, a metoda nie może być statyczna (do ich utworzenia potrzebna jest instancja klasy zewnętrznej, referencja do klasy instancja obiektu wywołującego jest domyślnie przekazywana do metod niestatycznych, a w metodzie statycznej nie ma metody dla tego łącza). Ale mają swoje własne cechy:
  1. Klasy lokalne mogą działać tylko ze zmiennymi metody końcowej. Rzecz w tym, że po zakończeniu metody instancje klas lokalnych można przechowywać na stercie, a zmienną można wymazać. Jeśli zmienna zostanie zadeklarowana jako ostateczna, kompilator może zapisać kopię zmiennej do późniejszego wykorzystania przez obiekt. I jeszcze jedno: od wersji Java 8+ można używać zmiennych niekońcowych w klasach lokalnych, ale tylko pod warunkiem, że nie ulegną one zmianie.
  2. Nie można deklarować klas lokalnych z modyfikatorami dostępu.
  3. Klasy lokalne mają dostęp do zmiennych metod.
Klasy lokalne można spotkać niezwykle rzadko, gdyż utrudniają czytanie kodu i nie mają żadnych zalet poza jedną - dostępem do zmiennych metod. Nie wiem, jaki przykład klasy lokalnej można wziąć, który pokazałby ich efektywne wykorzystanie, więc pokażę tylko mój przykład. Załóżmy, że mamy klasę Person(założymy, że jest to osoba) z właściwościami street(ulica), house(dom). Chcielibyśmy zwrócić jakiś obiekt, aby uzyskać dostęp tylko do lokalizacji danej osoby. W tym celu stworzyliśmy interfejs AddressContainer, który zakłada przechowywanie danych o lokalizacji danej osoby.
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
}
Jak widać, wewnątrz metody stworzyliśmy klasę implementującą zapamiętywanie lokalizacji osoby, utworzyliśmy tam zmienne stałe (tak, aby po wyjściu z metody zmienne były przechowywane w obiekcie) oraz zaimplementowaliśmy metodę pozyskiwania adresu i dom. Teraz możemy użyć tego obiektu w innych miejscach programu, aby uzyskać lokalizację osoby. Rozumiem, że ten przykład nie jest idealny i bardziej poprawne byłoby zrobienie tego po prostu zostawiając gettery w klasie Person, jednak pokazano utworzenie tej klasy i możliwe jej wykorzystanie, a potem decyzja należy do Ciebie.

Zajęcia anonimowe

W rzeczywistości klasy anonimowe to zwykłe, niestatyczne klasy zagnieżdżone. Ich cechą charakterystyczną jest łatwość użycia. Możesz napisać swoją klasę bezpośrednio podczas tworzenia instancji innej klasy.
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!");
        }
    }
}
Zasadniczo łączymy po prostu dwie rzeczy w jednym miejscu: tworzymy instancję jednej klasy ( Animal) i tworzymy instancję jej wewnętrznej klasy dziedziczącej ( Tiger). W przeciwnym razie musimy utworzyć klasę osobno i użyć dłuższych konstrukcji, aby osiągnąć ten sam wynik. Stosowanie zajęć anonimowych jest w wielu przypadkach uzasadnione, w szczególności gdy:
  • ciało klasy jest bardzo krótkie;
  • potrzebna jest tylko jedna instancja klasy;
  • klasa jest używana w miejscu, w którym została utworzona lub bezpośrednio po niej;
  • Nazwa klasy nie jest istotna i nie ułatwia zrozumienia kodu.
Klasy anonimowe są często używane w graficznych interfejsach użytkownika do tworzenia procedur obsługi zdarzeń. Na przykład, aby utworzyć przycisk i zareagować na jego kliknięcie:
JButton b2 = new JButton("Click");
b2.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        System.out.println("Кнопка нажата!");
    }
});
Jednak po Javie 8 zaczęto używać wyrażeń lambda, ale nadal dużo kodu zostało napisane przed wersją 8 i możesz napotkać (i napotkasz podczas szkolenia w JavaRush) takie napisy.\ Analogicznie z lambdami:
JButton b2 = new JButton("Click");
b2.addActionListener(e -> System.out.println("Кнопка нажата!"));
Koniec artykułu Dziękuję wszystkim za uwagę i mam nadzieję, że nauczyliście się czegoś nowego lub zrozumieliście coś, czego wcześniej nie rozumieliście. Pragnę również wyjaśnić, że artykuł ten należy do kategorii „dbałość o szczegóły” . Jest to moja pierwsza praca, więc mam nadzieję, że komuś się przydała. W najbliższym czasie, gdy przyjdą nowe pomysły, postaram się napisać coś innego, mam tylko jeden pomysł... Życzę wszystkim powodzenia i sukcesów w programowaniu :)
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION