JavaRush /Blog Java /Random-PL /Zagnieżdżone klasy wewnętrzne lub klasa wewnętrzna w Javi...

Zagnieżdżone klasy wewnętrzne lub klasa wewnętrzna w Javie

Opublikowano w grupie Random-PL
Cześć! Dzisiaj zaczniemy przyglądać się ważnemu tematowi - działaniu klas zagnieżdżonych w Javie. W języku angielskim nazywane są one klasami zagnieżdżonymi. Java pozwala na tworzenie niektórych klas wewnątrz innych:
class OuterClass {
    ...
    static class StaticNestedClass {
        ...
    }
    class InnerClass {
        ...
    }
}
To właśnie te klasy nazywane są zagnieżdżonymi. Dzielą się na 2 typy:
  1. Niestatyczne klasy zagnieżdżone - niestatyczne klasy zagnieżdżone. Nazywa się je także klasami wewnętrznymi w inny sposób.
  2. Statyczne klasy zagnieżdżone - statyczne klasy zagnieżdżone.
Z kolei klasy wewnętrzne mają dwa specjalne podtypy. Oprócz tego, że klasa wewnętrzna może być po prostu klasą wewnętrzną, może to być również:
  • klasa lokalna
  • klasa anonimowa
Troszke trudne? :) Nie ma problemu, oto diagram dla przejrzystości. Wróć do tego podczas wykładu, jeśli nagle poczujesz się zagubiony! Zagnieżdżone klasy wewnętrzne — 2Na dzisiejszym wykładzie porozmawiamy o klasach Inner - klasach wewnętrznych (są to także niestatyczne klasy zagnieżdżone, niestatyczne klasy zagnieżdżone). Są one specjalnie wyróżnione na ogólnym schemacie, żebyście się nie zgubili :) Zacznijmy od oczywistego pytania: dlaczego te klasy nazywają się „wewnętrznymi”? Odpowiedź jest dość prosta: ponieważ są tworzone wewnątrz innych klas. Oto przykład:
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("Iść!");
   }

   public class HandleBar {

       public void right() {
           System.out.println("Kierownica w prawo!");
       }

       public void left() {

           System.out.println("Kierownica w lewo!");
       }
   }

   public class Seat {

       public void up() {

           System.out.println("Siedzenie jest w górze!");
       }

       public void down() {

           System.out.println("Siedzenie jest opuszczone!");
       }
   }
}
Tutaj mamy klasę Bicycle- rower. Ma 2 pola i 1 metodę - start(). Zagnieżdżone klasy wewnętrzne — 3Różni się od zwykłej klasy tym, że ma dwie klasy, których kod jest zapisany w środku Bicycle- są to klasy HandleBar(kierownica) i Seat(fotel). Są to pełnoprawne klasy: jak widać, każda z nich ma swoje własne metody. W tym momencie możesz mieć pytanie: dlaczego umieściliśmy jedną klasę w drugiej? Po co umieszczać je wewnętrznie? OK, powiedzmy, że potrzebujemy w programie oddzielnych klas dla kierownicy i siedzenia. Ale nie musisz ich zagnieżdżać! Możesz robić regularne zajęcia. Na przykład tak:
public class HandleBar {
   public void right() {
       System.out.println("Kierownica w prawo!");
   }

   public void left() {

       System.out.println("kierownica lewa");
   }
}

public class Seat {

   public void up() {

       System.out.println("Siedzenie jest w górze!");
   }

   public void down() {

       System.out.println("Siedzenie jest opuszczone!");
   }
}
Bardzo dobre pytanie! Oczywiście nie mamy żadnych ograniczeń technicznych - możemy to zrobić w ten sposób. Chodzi raczej o prawidłowe zaprojektowanie zajęć z punktu widzenia konkretnego programu iw znaczeniu tego programu. Klasy wewnętrzne to klasy służące do wyróżniania w programie określonego elementu, który jest nierozerwalnie powiązany z innym obiektem. Kierownica, siodełko, pedały to elementy roweru. Oddzielone od roweru nie mają sensu. Gdybyśmy uczynili wszystkie te klasy oddzielnymi klasami publicznymi, nasz program mógłby mieć na przykład następujący kod:
public class Main {

   public static void main(String[] args) {
       HandleBar handleBar = new HandleBar();
       handleBar.right();
   }
}
Hmmm... Znaczenie tego kodu jest nawet trudne do wyjaśnienia. Mamy jakąś dziwną kierownicę rowerową (do czego jest potrzebna? Nie mam pojęcia, szczerze mówiąc). A ta kierownica skręca w prawo... sama, bez roweru... z jakiegoś powodu. Oddzielając istotę kierownicy od istoty roweru, zatraciliśmy logikę naszego programu. Używając klasy wewnętrznej, kod wygląda zupełnie inaczej:
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();
   }
}
Wyjście konsoli:

Сиденье поднято выше!
Поехали!
Руль влево!
Руль вправо!
To, co się działo, nagle nabrało sensu! :) Stworzyliśmy obiekt rowerowy. Stworzyliśmy dwa z jego „podobiektów” – kierownicę i siedzenie. Dla wygody podnieśliśmy siedzenie wyżej i ruszyliśmy: toczymy się i kierujemy tam, gdzie chcemy! :) Metody, których potrzebujemy, wywoływane są na niezbędnych obiektach. Wszystko jest proste i wygodne. W tym przykładzie podświetlenie kierownicy i siodełka poprawia enkapsulację (ukrywamy dane o częściach roweru w ramach odpowiedniej klasy) i pozwala nam stworzyć bardziej szczegółową abstrakcję. Spójrzmy teraz na inną sytuację. Załóżmy, że chcemy stworzyć program modelujący sklep z rowerami i częściami. Zagnieżdżone klasy wewnętrzne — 4W tej sytuacji nasze poprzednie rozwiązanie zakończy się niepowodzeniem. W sklepie z częściami każda pojedyncza część roweru ma znaczenie nawet poza samą istotą roweru. Na przykład będziemy potrzebować metod takich jak „sprzedaj pedały kupującemu”, „kup nowe siedzenie” itp. Błędem byłoby wykorzystywanie tutaj klas wewnętrznych – każda pojedyncza część roweru w naszym nowym programie ma swoje znaczenie: jest oddzielona od istoty roweru i nie jest z nią w żaden sposób powiązana. Na to powinieneś zwrócić uwagę, jeśli zastanawiasz się, czy potrzebujesz użyć klas wewnętrznych, czy też podzielić wszystkie byty na osobne klasy. Programowanie obiektowe jest świetne, ponieważ ułatwia modelowanie obiektów ze świata rzeczywistego. Tego możesz użyć jako wskazówki przy podejmowaniu decyzji o użyciu klas wewnętrznych. W prawdziwym sklepie części są oddzielone od rowerów - to normalne. Oznacza to, że będzie to poprawne podczas projektowania programu. OK, wyjaśniliśmy „filozofię” :) Teraz zapoznajmy się z ważnymi „technicznymi” cechami klas wewnętrznych. Oto, co zdecydowanie musisz zapamiętać i zrozumieć:
  1. Obiekt klasy wewnętrznej nie może istnieć bez obiektu klasy „zewnętrznej”.

    To logiczne: dlatego zrobiliśmy z tego zajęcia Seatwewnętrzne HandleBar, aby kierownice i fotele bez właściciela nie pojawiały się tu i ówdzie w naszym programie.

    Ten kod się nie skompiluje:

    public static void main(String[] args) {
    
       HandleBar handleBar = new HandleBar();
    }

    Wynika z tego następująca ważna cecha:

  2. Obiekt klasy wewnętrznej ma dostęp do zmiennych klasy „zewnętrznej”.

    Przykładowo dodajmy do naszej klasy Bicyclezmienną int seatPostDiameter– średnicę sztycy.

    Następnie w klasie wewnętrznej Seatmożemy stworzyć metodę getSeatParam(), która poinformuje nas o parametrze seat:

    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("Iść!");
       }
    
       public class Seat {
    
           public void up() {
    
               System.out.println("Siedzenie jest w górze!");
           }
    
           public void down() {
    
               System.out.println("Siedzenie jest opuszczone!");
           }
    
           public void getSeatParam() {
    
               System.out.println("Parametr siodła: średnica sztycy = " + Bicycle.this.seatPostDiameter);
           }
       }
    }

    A teraz możemy uzyskać te informacje w naszym programie:

    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
           Bicycle.Seat seat = bicycle.new Seat();
    
           seat.getSeatParam();
       }
    }

    Wyjście konsoli:

    
    Параметр сиденья: диаметр подседельного штыря = 40

    Zwróć uwagę:nowa zmienna jest deklarowana z najsurowszym modyfikatorem - private. A mimo to klasa wewnętrzna ma dostęp!

  3. Obiektu klasy wewnętrznej nie można utworzyć w metodzie statycznej klasy „zewnętrznej”.

    Wyjaśnia to cechy konstrukcyjne klas wewnętrznych. Klasa wewnętrzna może mieć konstruktory z parametrami lub tylko konstruktor domyślny. Ale niezależnie od tego, kiedy tworzymy obiekt klasy wewnętrznej, po cichu przekazywana jest do niego referencja do obiektu klasy „zewnętrznej”. W końcu obecność takiego obiektu jest warunkiem wstępnym. W przeciwnym razie nie będziemy mogli stworzyć obiektów klasy wewnętrznej.

    Ale jeśli metoda klasy zewnętrznej jest statyczna, wówczas obiekt klasy zewnętrznej może w ogóle nie istnieć! Oznacza to, że logika klasy wewnętrznej zostanie złamana. W takiej sytuacji kompilator zgłosi błąd:

    public static Seat createSeat() {
    
       //Bicycle.this cannot be referenced from a static context
       return new Seat();
    }
  4. Klasa wewnętrzna nie może zawierać zmiennych i metod statycznych.

    Logika tutaj jest taka sama: metody i zmienne statyczne mogą istnieć i być wywoływane nawet jeśli nie ma obiektu.

    Ale bez obiektu klasy „zewnętrznej” nie będziemy mieli dostępu do klasy wewnętrznej.

    Oczywista sprzeczność! Dlatego obecność zmiennych i metod statycznych w klasach wewnętrznych jest zabroniona.

    Kompilator zgłosi błąd podczas próby ich utworzenia:

    public class Bicycle {
    
       private int weight;
    
    
       public class Seat {
    
           //inner class cannot have static declarations
           public static void getSeatParam() {
    
               System.out.println("Parametr siodła: średnica sztycy = " + Bicycle.this.seatPostDiameter);
           }
       }
    }
  5. Podczas tworzenia obiektu klasy wewnętrznej ważną rolę odgrywa jego modyfikator dostępu.

    Klasę wewnętrzną można oznaczyć za pomocą standardowych modyfikatorów dostępu - public, i .privateprotectedpackage private

    Dlaczego to jest ważne?

    Ma to wpływ na to, gdzie w naszym programie możemy utworzyć instancję klasy wewnętrznej.

    Jeśli nasza klasa Seatjest zadeklarowana jako public, możemy utworzyć jej obiekty w dowolnej innej klasie. Jedynym wymaganiem jest to, że musi także istnieć obiekt klasy „zewnętrznej”.

    Nawiasem mówiąc, już to zrobiliśmy tutaj:

    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();
       }
    }

    Z łatwością uzyskaliśmy dostęp do klasy wewnętrznej HandleBarz Main.

    Jeśli zadeklarujemy klasę wewnętrzną jako private, będziemy mieli dostęp tylko do tworzenia obiektów w obrębie klasy „zewnętrznej”.

    SeatNie będziemy już mogli stworzyć obiektu z zewnątrz:

    private class Seat {
    
       //metody
    }
    
    public class Main {
    
       public static void main(String[] args) {
    
           Bicycle bicycle = new Bicycle("Peugeot", 120, 40);
    
           //Bicycle.Seat has a private access in 'Bicycle'
           Bicycle.Seat seat = bicycle.new Seat();
       }
    }

    Pewnie już rozumiesz logikę :)

  6. Modyfikatory dostępu dla klas wewnętrznych działają tak samo jak w przypadku zwykłych zmiennych.

    Modyfikator protectedzapewnia dostęp do zmiennej klasy w jej klasach potomnych oraz w klasach znajdujących się w tym samym pakiecie.

    To samo protecteddotyczy klas wewnętrznych. Obiekty protectedklas wewnętrznych można tworzyć:

    • wewnątrz klasy „zewnętrznej”;
    • w swoich klasach potomnych;
    • w tych klasach, które są w tym samym pakiecie.

    Jeśli klasa wewnętrzna nie ma modyfikatora dostępu ( package private), można utworzyć obiekty klasy wewnętrznej

    • wewnątrz klasy „zewnętrznej”;
    • w klasach znajdujących się w tym samym pakiecie.

    Modyfikatory znasz od dawna, więc tutaj nie będzie żadnych problemów.

To wszystko na teraz :) Ale nie relaksuj się! Wewnętrzne klasy zagnieżdżone to dość szeroki temat, który będziemy kontynuować w przyszłych lekcjach. Teraz możesz odświeżyć wykład na zajęciach wewnętrznych z naszego kursu. Następnym razem porozmawiamy o statycznych klasach zagnieżdżonych.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION