programowanieProgramista Backend

Jak działa mechanizm modyfikatorów widoczności (internal/private/protected/public) dla funkcji i właściwości na najwyższym poziomie w Kotlin? Jakie są różnice w porównaniu z Javą i jakie niuanse należy wziąć pod uwagę?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź.

W Kotlinie modyfikatory widoczności umożliwiają kontrolowanie dostępu do deklaracji: klas, właściwości, funkcji oraz elementów na najwyższym poziomie (na poziomie pliku). W przeciwieństwie do Javy, gdzie modyfikatory działają tylko na poziomie klasy, w Kotlinie działają również dla deklaracji na najwyższym poziomie, co jest ważne dla strukturyzacji dużych projektów i API bibliotek.

Historia pytania

W Javie nie ma modyfikatorów widoczności dla funkcji lub właściwości poza klasą – wszystko znajduje się w publicznej (lub pakietowo-prywatnej) klasie. W Kotlinie przyjęto inne podejście do strukturyzacji projektu, często funkcja lub właściwość znajduje się nie wewnątrz klasy, ale bezpośrednio w pliku.

Problem

Często programiści Javy oczekują, że publiczne domyślnie będzie działać tak samo jak w Javie, ale w Kotlinie funkcja (lub właściwość) na najwyższym poziomie jest widoczna we wszystkich modułach, chyba że oznaczona jest inaczej. Niewłaściwe określenie widoczności może prowadzić do zanieczyszczenia publicznego API, nieoczekiwanej dostępności wewnętrznych narzędzi lub niedostępności potrzebnych publicznych funkcji.

Rozwiązanie

W Kotlinie dostępne są następujące modyfikatory:

  • public: deklaracja widoczna wszędzie (jest modyfikatorem domyślnym dla najwyższego poziomu).
  • internal: deklaracja widoczna we wszystkich plikach tego samego modułu (jednego modułu gradle, jednego artefaktu kompilowanego, jednego jar).
  • private: widoczna tylko w tym samym pliku/klasie, gdzie została zadeklarowana. Dla najwyższego poziomu - tylko wewnątrz pliku.
  • protected: nie ma zastosowania dla deklaracji na najwyższym poziomie, tylko dla klas/interfejsów i ich dziedziczących.

Przykład:

// plik: Foo.kt private fun utilityFun() {} internal val bar: Int = 10 public val baz: Int = 20 // public nie jest wymagany fun printValue() { println(bar) }

Kluczowe cechy:

  • internal ogranicza widoczność do modułu (jar/artefakt), a nie do pakietu.
  • protected nie może być używane dla funkcji lub właściwości na najwyższym poziomie.
  • private w najwyższym poziomie ogranicza deklarację do bieżącego pliku.

Pytania z pułapką.

Czy można użyć protected dla funkcji na najwyższym poziomie?

Nie, protected dotyczy tylko członków klasy/interfejsu, elementy na najwyższym poziomie tego nie wspierają.

Jeśli zadeklaruję funkcję na najwyższym poziomie z internal, czy będzie widoczna w innych modułach?

Nie. Będzie widoczna tylko w granicach bieżącego modułu jar/Gradle.

Czym różni się private class od private top-level function?

  • private class: widoczny tylko w bieżącym pliku, nie może być używany poza plikiem.
  • private top-level function lub właściwość: podobnie widoczny tylko wewnątrz pliku.

Przykład:

// plik: Utils.kt private fun helper() { /* ... */ } // widoczny tylko w tym pliku internal fun useful() { /* ... */ } // widoczny w całym module

Typowe błędy i antywzorce

  • Użycie public domyślnie dla wszystkich deklaracji prowadzi do „zanieczyszczenia” autouzupełniania i API.
  • Użycie internal dla biblioteki przeznaczonej dla zewnętrznych klientów ukrywa potrzebne publiczne API.
  • Pomieszanie z protected i próby ich stosowania na najwyższym poziomie.

Przykład z życia

Negatywny przypadek

Funkcje pomocnicze są zadeklarowane jako public, przez co trafiają do artefaktu, przeszkadzając klientowi biblioteki – staje się widoczne wszystko, co nie należy do publicznego API.

Zalety:

  • Szybka integracja.

Wady:

  • Wzrasta rozmiar publicznego API, pojawiają się „przypadkowe” metody w dostępie.

Pozytywny przypadek

Funkcje wewnętrzne są zadeklarowane jako private, narzędzia z widocznością internal do wspólnego użytku w module, tylko starannie przemyślane interfejsy mają dostęp publiczny.

Zalety:

  • Jasna, czysta struktura API.
  • Minimalizowane przypadkowe zależności.

Wady:

  • Konieczność przemyślenia struktury projektu.