ProgrammazioneSviluppatore Backend

Spiega le sottigliezze dell'uso dell'operatore 'object' in Kotlin: cosa sono gli oggetti singleton, le espressioni oggetto, le dichiarazioni oggetto e gli oggetti compagni. Fai degli esempi di utilizzo e possibili errori.

Supera i colloqui con l'assistente IA Hintsage

Risposta.

Kotlin espande il concetto classico di singleton attraverso la parola chiave object. Con essa si realizzano i seguenti pattern:

  • Dichiarazione oggetto (object declaration) — crea un'unica istanza per tutta l'applicazione (object Logger { ... }).
  • Espressione oggetto (object expression) — crea un oggetto anonimo direttamente nel luogo di utilizzo, ad esempio per implementare interfacce o gestori di eventi.
  • Oggetti compagni (companion object) — consentono di dichiarare membri statici in una classe.

Esempio di singleton:

object DatabaseManager { fun connect() { /*...*/ } } DatabaseManager.connect()

Espressione oggetto:

val listener = object : MouseAdapter() { override fun mouseClicked(e: MouseEvent) { /*...*/ } }

Oggetto compagno:

class User { companion object Factory { fun create(name: String) = User() } } val user = User.create("Ivan")

Sottigliezze:

  • Gli oggetti compagni sono visibili come campi statici a livello di bytecode.
  • Gli oggetti compagni possono implementare interfacce.
  • L'espressione oggetto non è un singleton, viene creata ogni volta che viene chiamata.
  • La dichiarazione oggetto è inizializzata pigramente, al primo accesso.

Domanda insidiosa.

Qual è la differenza tra companion object e object declaration? Tutti i loro membri sono accessibili come statici?

Risposta:

  • object declaration — singleton globale, membro di una classe, interfaccia o livello esterno.
  • companion object — un tipo speciale di object declaration all'interno di una classe, i cui membri possono essere chiamati come se fossero statici (attraverso il nome della classe). Tuttavia, a differenza di Java, sono in realtà campi di un oggetto singleton.

Esempio della differenza:

class A { companion object { fun foo() {} } object NestedObj { fun bar() {} } } A.foo() // OK A.NestedObj.bar() // OK, ma non è un metodo statico

Esempi di errori reali a causa della mancanza di conoscenza delle sottigliezze dell'argomento.


Storia

Lo sviluppatore ha definito uno stato mutabile all'interno di una dichiarazione oggetto e ha iniziato a usarlo da diversi thread senza sincronizzazione, ignorando che gli oggetti singleton sono condivisi da tutta l'applicazione e possono causare condizioni di gara.


Storia

Durante la dichiarazione di un oggetto anziché un oggetto compagno all'interno di una classe si rendeva necessario utilizzare metodi statici, ma dovevano essere chiamati tramite un'istanza, il che ha ridotto la leggibilità e ha causato errori durante la migrazione da Java.


Storia

Nel codice UI, il programmatore creava ogni volta un nuovo oggetto tramite un'espressione oggetto per un gestore di eventi. Pensava erroneamente che fosse un singleton e che lo stato venisse mantenuto; di conseguenza si sono verificate perdite di memoria a causa della gestione scorretta del ciclo di vita.