ProgrammazioneSviluppatore Backend

Come funziona il meccanismo dei modificatori di visibilità (internal/private/protected/public) per funzioni e proprietà di livello superiore in Kotlin? Quali sono le differenze rispetto a Java e quali accorgimenti dovrebbe considerare?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

In Kotlin, i modificatori di visibilità consentono di controllare l'accesso alle dichiarazioni: classi, proprietà, funzioni e entità di livello superiore (a livello di file). A differenza di Java, dove i modificatori operano solo a livello di classe, in Kotlin funzionano anche per le dichiarazioni di livello superiore, il che è importante per strutturare grandi progetti e API di librerie.

Storia della questione

In Java non ci sono modificatori di visibilità per funzioni o proprietà al di fuori della classe: tutto è racchiuso all'interno di una classe public (o package-private). In Kotlin è comune strutturare il progetto in modo diverso, spesso una funzione o una proprietà si trova non all'interno di una classe, ma direttamente nel file.

Problema

Spesso gli sviluppatori Java si aspettano che public per impostazione predefinita funzioni come in Java, ma in Kotlin, una funzione di livello superiore (o proprietà) è visibile in tutti i moduli, se non diversamente contrassegnata. Una definizione scorretta della visibilità può portare a un inquinamento lessicale dell'API pubblica, una disponibilità inaspettata di utility interne, oppure all'inaccessibilità di funzioni pubbliche necessarie.

Soluzione

In Kotlin sono disponibili i seguenti modificatori:

  • public: la dichiarazione è visibile ovunque (è il modificatore predefinito per le entità di livello superiore).
  • internal: la dichiarazione è visibile in tutti i file dello stesso modulo (un modulo gradle, un artefatto compilato, un jar).
  • private: visibile solo nello stesso file/classe in cui è stata dichiarata. Per le entità di livello superiore: solo all'interno del file.
  • protected: non applicabile alle dichiarazioni di livello superiore, solo a classi/interfacce e ai loro eredi.

Esempio:

// file: Foo.kt private fun utilityFun() {} internal val bar: Int = 10 public val baz: Int = 20 // public non è necessario fun printValue() { println(bar) }

Caratteristiche chiave:

  • internal limita la visibilità al modulo (jar/artefatto), non al pacchetto.
  • protected non può essere utilizzato per funzioni o proprietà di livello superiore.
  • private in livello superiore limita la dichiarazione all'interno del file corrente.

Domande trabocchetto.

È possibile utilizzare protected per una funzione di livello superiore?

No, protected è pertinente solo ai membri di classi/interfacce, le entità di livello superiore non supportano tali elementi.

Se dichiaro una funzione di livello superiore con internal, sarà visibile all'interno di altri moduli?

No. Sarà visibile solo all'interno del modulo jar/Gradle corrente.

Qual è la differenza tra una classe privata e una funzione di livello superiore privata?

  • classe privata: visibile solo all'interno del file corrente, non può essere utilizzata al di fuori del file.
  • funzione o proprietà di livello superiore privata: analogamente visibile solo all'interno del file.

Esempio:

// file: Utils.kt private fun helper() { /* ... */ } // visibile solo in questo file internal fun useful() { /* ... */ } // visibile in tutto il modulo

Errori tipici e anti-pattern

  • L'uso di public per impostazione predefinita per tutte le dichiarazioni porta a "inquinamento" dell'autocompletamento e dell'API.
  • L'uso di internal per una libreria destinata a clienti esterni nasconde le necessarie API pubbliche.
  • Confusione con protected e tentativi di applicarli a livello superiore.

Esempio dalla vita reale

Caso negativo

Le utility di test sono dichiarate public e dunque entrano nell'artefatto, ostacolando il client della libreria: diventa visibile tutto ciò che non è legato all'API pubblica.

Pro:

  • Integrazione rapida.

Contro:

  • Crescita della dimensione dell'API pubblica, emergere di metodi "casuali" in accesso.

Caso positivo

Funzioni interne dichiarate private, utility con visibilità interna per uso comune all'interno del modulo, solo interfacce attentamente progettate hanno accesso pubblico.

Pro:

  • Struttura API chiara e pulita.
  • Minimizzazione delle dipendenze casuali.

Contro:

  • Necessità di progettare la struttura del progetto.