Cześć! Kontynuujemy zgłębianie tematu klas zagnieżdżonych w Javie. Na ostatniej lekcji mówiliśmy o niestatycznych klasach zagnieżdżonych lub, jak się je nazywa, klasach wewnętrznych. Dziś przejdźmy do innej grupy i przyjrzyjmy się bliżej statycznym klasom zagnieżdżonym. Czym różnią się od innych grup? Deklarując taką klasę, używamy znanego już słowa kluczowego static:
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
public static int getMaxPassengersCount() {
return maxPassengersCount;
}
}
}
W tym przykładzie mamy klasę zewnętrzną Boeing737
, która tworzy samolot tego modelu. I ma konstruktora z jednym parametrem: rokiem produkcji ( int manufactureYear
). Jest jeszcze jedna zmienna statyczna int maxPassengersCount
– maksymalna liczba pasażerów. Będzie taki sam dla wszystkich samolotów tego samego modelu, dlatego potrzebujemy tylko jednego egzemplarza. Dodatkowo posiada statyczną klasę wewnętrzną Drawing
– plan samolotu. W tej klasie możemy zawrzeć wszystkie informacje serwisowe dotyczące samolotu. W naszym przykładzie dla uproszczenia ograniczyliśmy go do roku produkcji, ale może zawierać wiele innych informacji. Jak omawialiśmy w ostatnim wykładzie, utworzenie takiej zagnieżdżonej klasy zwiększa hermetyzację i promuje bardziej realistyczną abstrakcję. Jaka jest różnica między statycznymi i niestatycznymi klasami zagnieżdżonymi? 1. Obiekt klasy statycznej Drawing
nie przechowuje odniesienia do konkretnej instancji klasy zewnętrznej. Przypomnijcie sobie przykład z ostatniego wykładu z rowerem:
public class Bicycle {
private String model;
private int mawWeight;
public Bicycle(String model, int mawWeight) {
this.model = model;
this.mawWeight = mawWeight;
}
public void start() {
System.out.println("Iść!");
}
public class SteeringWheel {
public void right() {
System.out.println("Kierownica w prawo!");
}
public void left() {
System.out.println("Kierownica w lewo!");
}
}
}
Mówiliśmy tam o tym, jak SteeringWheel
referencja do obiektu klasy zewnętrznej (rower) jest przekazywana do każdej instancji klasy wewnętrznej (kierownica) w niezauważalny sposób Bicycle
. Bez obiektu klasy zewnętrznej obiekt klasy wewnętrznej po prostu nie mógłby istnieć. Nie dotyczy to statycznych klas zagnieżdżonych. Obiekt statycznej klasy zagnieżdżonej może z łatwością istnieć samodzielnie. Pod tym względem klasy statyczne są bardziej „niezależne” niż klasy niestatyczne. Jedynym punktem jest to, że podczas tworzenia takiego obiektu należy podać nazwę klasy zewnętrznej:
public class Main {
public static void main(String[] args) {
Boeing737.Drawing drawing1 = new Boeing737.Drawing();
Boeing737.Drawing drawing2 = new Boeing737.Drawing();
}
}
Dlaczego założyliśmy zajęcia Drawing
statyczne, podczas gdy na ostatnim wykładzie zajęcia Seat
(fotelik rowerowy) były niestatyczne? Podobnie jak ostatnim razem, dodajmy trochę „filozofii”, aby zrozumieć przykład :) W przeciwieństwie do fotelika rowerowego, istota rysunku nie jest tak ściśle powiązana z istotą samolotu. Oddzielny obiekt do siedzenia, bez roweru, najczęściej będzie pozbawiony sensu (choć nie zawsze – mówiliśmy o tym na ostatniej lekcji). Istota rysunku ma sens sama w sobie. Na przykład może być przydatny dla inżynierów planujących naprawy samolotów. Nie potrzebują samego samolotu do planowania i można je umieścić w dowolnym miejscu - wystarczy rysunek. Poza tym dla wszystkich samolotów tego samego modelu rysunek nadal będzie taki sam, więc nie ma tak sztywnego połączenia jak fotelik z rowerem. Dlatego obiekt Drawing
nie wymaga powiązania z konkretnym obiektem statku powietrznego. 2. Różny dostęp do zmiennych i metod klasy zewnętrznej. Statyczna klasa zagnieżdżona może uzyskać dostęp tylko do pól statycznych klasy zewnętrznej. W naszym przykładzie klasa Drawing
posiada metodę getMaxPassengersCount()
zwracającą wartość zmiennej statycznej maxPassengersCount
z klasy zewnętrznej. Nie możemy jednak utworzyć metody getManufactureYear()
zwracającej Drawing
wartość manufactureYear
. W końcu zmienna manufactureYear
jest niestatyczna, co oznacza, że musi należeć do konkretnej instancji Boeing737
. A jak już się przekonaliśmy, w przypadku statycznych klas zagnieżdżonych łatwo może zabraknąć obiektu klasy zewnętrznej. Stąd ograniczenie :) Nie ma znaczenia, jaki modyfikator dostępu ma zmienna statyczna w klasie zewnętrznej. Nawet jeśli tak jest private
, dostęp ze statycznej klasy zagnieżdżonej będzie nadal możliwy. Wszystko to dotyczy nie tylko dostępu do zmiennych statycznych, ale także do metod statycznych. WAŻNY! Słowo static
w deklaracji klasy wewnętrznej nie oznacza, że można utworzyć tylko jeden obiekt. Nie myl obiektów ze zmiennymi. Jeśli mówimy o zmiennych statycznych, tak, na przykład zmienna klasy statycznej maxPassangersCount
istnieje w jednej kopii. Ale zastosowane do klasy zagnieżdżonej static
oznacza tylko, że jej obiekty nie zawierają odniesień do obiektów klasy zewnętrznej. I możemy stworzyć dowolną liczbę obiektów:
public class Boeing737 {
private int manufactureYear;
private static int maxPassengersCount = 300;
public Boeing737(int manufactureYear) {
this.manufactureYear = manufactureYear;
}
public int getManufactureYear() {
return manufactureYear;
}
public static class Drawing {
private int id;
public Drawing(int id) {
this.id = id;
}
public static int getPassengersCount() {
return maxPassengersCount;
}
@Override
public String toString() {
return "Drawing{" +
"id=" + id +
'}';
}
public static void main(String[] args) {
for (int i = 1; i < 6; i++) {
Boeing737.Drawing drawing = new Boeing737.Drawing(i);
System.out.println(drawing);
}
}
}
}
Zadeklarowaliśmy metodę main()
bezpośrednio w klasie zagnieżdżonej (nie ma ku temu szczególnego powodu – tak po prostu, żebyś wiedział, że jest to możliwe) i utworzyliśmy 5 obiektów Drawing
. Pomimo tego, że nie mamy ani jednego obiektu klasy zewnętrznej. Jak widać nie było żadnych problemów :) Dane wyjściowe z konsoli:
Drawing{id=1}
Drawing{id=2}
Drawing{id=3}
Drawing{id=4}
Drawing{id=5}
Na tym kończymy naszą lekcję! Na wszelki wypadek zostawiam link do sekcji o nich w dokumentacji Oracle . Przeczytaj, jeśli są jakieś niejasne punkty. Teraz czas rozwiązać kilka problemów! :)
GO TO FULL VERSION