Po co są konstruktory
Na poprzedniej stronie budowałeś klasy i tworzyłeś obiekty przez new. Konstruktor to kod, który faktycznie wykonuje się podczas wywołania new. Jego jedynym celem jest zwrócenie obiektu gotowego do użycia: ze wszystkimi wymaganymi polami ustawionymi i bez częściowo zainicjalizowanego stanu.
Konstruktor wygląda jak metoda, ale z dwiema różnicami: ma taką samą nazwę jak klasa i nie ma typu zwracanego, nawet void.
new Point(3, 4) przydziela pamięć na obiekt, a potem wykonuje ciało konstruktora z x = 3 i y = 4. Zanim new zwróci wynik, p jest w pełni zainicjalizowany.
Słowo kluczowe this
W konstruktorze powyżej parametry nazywają się x i y, tak samo jak pola. this.x oznacza „pole x należące do tego obiektu”, a samo x odnosi się do parametru. Bez this zapis x = x przypisałby parametr samemu sobie i nie zmieniłby pola.
this jest konieczne tylko wtedy, gdy parametr przesłania pole, ale wiele osób używa go wszędzie dla przejrzystości. Częsty błąd to zapomnienie o nim przy kolizji nazw: kod się kompiluje, działa i po cichu zostawia pola z wartościami domyślnymi (null, 0, false).
Konstruktor domyślny
Jeśli nigdy nie napiszesz konstruktora, Java po cichu dostarcza konstruktor domyślny: publiczny, bezargumentowy konstruktor, który nie robi nic dodatkowego. Dlatego new działało dla klas, które w ogóle nie miały konstruktora.
Haczyk: gdy tylko napiszesz jakikolwiek konstruktor, darmowy znika.
class Box {
int size;
Box(int size) { // teraz NIE ma konstruktora bezargumentowego
this.size = size;
}
}
new Box(); // błąd kompilacji: nie istnieje konstruktor Box()
Jeśli nadal chcesz, by działało new Box(), sam zadeklaruj konstruktor bezargumentowy:
Przeciążanie konstruktorów
Klasa może mieć kilka konstruktorów, o ile różnią się listą parametrów: to po prostu przeciążanie metod zastosowane do konstruktorów. Każdy z nich oferuje inny sposób zbudowania obiektu.
Java wybiera pasujący konstruktor na podstawie liczby i typów argumentów przekazanych do new.
Łańcuchowanie przez this()
Zauważ powtórzenia powyżej: każdy konstruktor sam przypisuje pola. Możesz tego uniknąć, gdy jeden konstruktor wywołuje inny przez this(...). To wywołanie musi być pierwszą instrukcją w konstruktorze.
Teraz właściwa inicjalizacja jest w jednym miejscu. Mniejsze konstruktory tylko uzupełniają wartości domyślne i przekazują pracę dalej. Jeśli spróbujesz umieścić jakąś instrukcję przed this(...), kompilator to odrzuci.
Konstruktory i super()
Każdy konstruktor najpierw niejawnie wywołuje konstruktor nadklasy. Jeśli nic nie napiszesz, Java wstawia na początku ciała ukryte super() (bezargumentowy konstruktor nadklasy). Zaczniesz z tym pracować bezpośrednio, gdy zaczniesz tworzyć podklasy, a to temat następnej strony.
class Animal {
String name;
Animal(String name) { this.name = name; }
}
class Dog extends Animal {
Dog(String name) {
super(name); // tu trzeba jawnie wywołać konstruktor rodzica
}
}
Animal nie ma konstruktora bezargumentowego, więc Dog musi jawnie wywołać super(name): nie ma darmowego super(), na którym mógłby polegać. Podobnie jak this(), wywołanie super(...) musi być pierwszą instrukcją w konstruktorze.
Dalej: dziedziczenie
Konstruktory inicjalizują pojedynczy obiekt, ale super() już zasugerowało coś większego: klasy mogą budować na innych klasach i ponownie wykorzystywać ich pola, metody i konstruktory. Ta relacja, w której jedna klasa rozszerza inną, to dziedziczenie. Omawia je następna strona.
Najczęściej zadawane pytania
Czym jest konstruktor w Javie?
Konstruktor to specjalna metoda, która uruchamia się, gdy tworzysz obiekt przez new. Ma taką samą nazwę jak klasa i nie ma typu zwracanego (nawet void). Jego zadaniem jest nadanie nowemu obiektowi poprawnego stanu początkowego, zwykle przez przypisanie argumentów konstruktora do pól obiektu.
Czym różni się konstruktor od metody w Javie?
Konstruktor ma dokładnie taką samą nazwę jak klasa, nie deklaruje typu zwracanego i można go wywołać tylko przez new przy tworzeniu obiektu. Zwykła metoda ma własną nazwę, deklaruje typ zwracany (lub void) i wywołuje się ją na istniejącym obiekcie. Konstruktory inicjalizują, a metody wykonują pracę później.
Co się stanie, jeśli nie napiszę konstruktora w Javie?
Kompilator daje ci za darmo bezargumentowy konstruktor domyślny, który nie przyjmuje parametrów i nie robi nic poza niejawnym wywołaniem super(). Gdy jednak sam napiszesz jakikolwiek konstruktor, ten darmowy znika. Jeśli więc dodasz konstruktor z parametrami i nadal chcesz, by działało new Thing(), musisz jawnie zadeklarować konstruktor bezargumentowy.