programowanieProgramista Android

Jak działają modyfikatory widoczności (visibility modifiers) w Kotlin: internal, private, protected, public? Czym różnią się modyfikatory w różnych kontekstach — dla klas, funkcji, właściwości, obiektów, funkcji na najwyższym poziomie i plików?

Zdaj rozmowy kwalifikacyjne z asystentem AI Hintsage

Odpowiedź

W Kotlinie istnieją następujące modyfikatory widoczności:

  • public (domyślnie): element widoczny wszędzie.
  • internal: element widoczny w ramach jednego modułu (jar/gradle module itd.).
  • protected: widoczny tylko wewnątrz klasy i jej dziedziców.
  • private: widoczny tylko w ramach pliku lub klasy.

Cechy szczególne:

  • Dla funkcji, właściwości i klas na najwyższym poziomie: private ogranicza dostęp do pliku, internal — do modułu, a public/protected nie ma sensu poza klasą.
  • Dla członków klasy: private — tylko w tej klasie, protected — dodatkowo dla dziedziców, internal i public — tak, jak opisano powyżej.
  • W obrębie obiektu/kompana obiektu: podobnie jak w klasie.
class MyClass { private val secret = "ukryty" protected val id = 42 internal fun foo() {} public fun bar() {} } internal fun moduleFunc() {} private fun fileOnlyFunc() {}

Pytanie z zaskoczeniem

"Czy funkcja na najwyższym poziomie może być protected? Jeśli tak — jak to działa? Jeśli nie — dlaczego?"

Odpowiedź: Nie, funkcja na najwyższym poziomie nie może być protected, ponieważ nie ma klasy, do której należy ten poziom dostępu. Odpowiada za to kompilator – pojawi się błąd kompilacji.

protected fun magic() {} // Błąd: modyfikator protected nie jest dozwolony dla funkcji na najwyższym poziomie

Przykłady rzeczywistych błędów z powodu nieznajomości niuansów tematu


Historia

W aplikacji fintech zapomniano, że modyfikator internal daje dostęp do wszystkich elementów modułu. W rezultacie podczas refaktoryzacji przeniesiono część logiki do innego modułu gradle, po czym przestał działać dostęp do danych, ale programiści nie zauważyli tego od razu, ponieważ na etapie kompilacji nie było błędów w starych testach.


Historia

W projekcie wieloplatformowym zdefiniowano poufne dane jako private właściwości w companion object. Okazało się, że te dane są serializowane i stają się dostępne przez reflection, ponieważ zostały zadeklarowane jako val bez użycia adnotacji ograniczających eksport.


Historia

Na początku projektu mobilnego stosowano private dla funkcji na najwyższym poziomie, sądząc, że ograniczy to dostęp dla klas partnerskich. Jednak w ramach wspólnego pliku z utils te funkcje były widoczne dla wszystkich, co prowadziło do zagrożenia wycieku informacji i nieprzewidzianego użycia w logice biznesowej.