programowanieProgramista Kotlin

Wyjaśnij szczegóły widoczności i dziedziczenia konstruktorów w Kotlinie: czym różnią się konstruktor pierwotny od konstruktorów wtórnych, niuanse dziedziczenia i modyfikatory widoczności. Podaj przykłady kodu i typowe błędy.

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

W Kotlinie każda klasa może mieć jeden konstruktor pierwotny (podawany w deklaracji klasy) i wiele konstruktorów wtórnych (poprzez constructor).

  • Konstruktor pierwotny nie może zawierać kodu poza deklaracją (logika - w init).
  • Konstruktor wtórny wdraża dodatkowe warianty inicjalizacji.
  • Jeśli rodzic nie ma konstruktora bez parametrów, dziedziczący musi jawnie wywołać jego konstruktor.
  • Dzięki modyfikatorom (private, protected, internal, public) można ukrywać lub ograniczać widoczność konstruktorów.

Przykład z konstruktorem pierwotnym i wtórnym:

open class Person(val name: String) { constructor(name: String, age: Int) : this(name) { // konstruktor wtórny } } class Employee : Person { constructor(name: String) : super(name) // Wymagane jest jawne super }

Modyfikatory widoczności:

class Secret private constructor() { companion object { fun create() = Secret() } } val s = Secret.create() // Ok, a Secret() - błąd

Niuanse:

  • Jeśli klasa z konstruktorem pierwotnym ma parametry, dziedziczenie bez przekazywania tych parametrów jest niemożliwe.
  • Konstruktorzy wtórni muszą pośrednio lub bezpośrednio wywoływać pierwotny.
  • Klasy zagnieżdżone nie mają dostępu do prywatnego konstruktora klasy zewnętrznej.

Pytanie podchwytliwe.

Czy w Kotlinie można dziedziczyć klasę i nie wywoływać jej pierwotnego konstruktora?

Odpowiedź: Nie. W Kotlinie w przypadku dziedziczenia zawsze musi zostać wywołany przynajmniej jeden konstruktor rodzica - czy to pierwotny, czy wtórny (poprzez super()).

Przykład:

open class A(val x: Int) class B: A // Błąd: wymaga jawnego wywołania konstruktora A

Przykłady rzeczywistych błędów z powodu braku znajomości szczegółów tematu.


Historia

W zespole próbowano zabronić tworzenia obiektów klasy bezpośrednio i zrobili konstruktor prywatny. Zapomniano jednak zaimplementować metodę fabryczną. Doprowadziło to do niemożności przetestowania klasy bez refleksji i zablokowania CI.


Historia

Dziedziczyli klasę z obowiązkowymi parametrami w konstruktorze pierwotnym, ale nie przekazali ich przy deklaracji dziedziczącego. To wykryto dopiero na etapie kompilacji po długim debugowaniu.


Historia

Podczas korzystania z konstruktorów wtórnych zapomniano, że wszystkie muszą wywoływać pierwotny. W rezultacie obiekty były inicjowane bez potrzebnych parametrów, co doprowadziło do NullPointerException w czasie wykonywania.