Unlimited Plugins, WordPress themes, videos & courses! Unlimited asset downloads! From $16.50/m
Advertisement
  1. Code
  2. Kotlin
Code

Kotlin From Scratch: Proprietà e classi avanzate

by
Difficulty:IntermediateLength:LongLanguages:
This post is part of a series called Kotlin From Scratch.
Kotlin From Scratch: Classes and Objects
Kotlin From Scratch: Abstract Classes, Interfaces, Inheritance, and Type Alias

Italian (Italiano) translation by Loris Pizii (you can also view the original English article)

Kotlin è un moderno linguaggio di programmazione che compone il bytecode di Java. È libero e open source e promette di rendere codifica per Android ancora più divertente.

Nell'articolo precedente, hai imparato su classi e oggetti in Kotlin. In questo tutorial, continueremo a saperne di più sulle proprietà e guardiamo anche in tipi avanzati di classi in Kotlin esplorando quanto segue:

  • proprietà inizializzate in ritardo
  • inline proprietà
  • proprietà di estensione
  • dati, enum, nidificati e classi sigillate

1. Proprietà in fase inizializzata

Possiamo dichiarare una proprietà non nullo in Kotlin come inizializzato in ritardo. Ciò significa che una proprietà non nullo non verrà inizializzata in fase di dichiarazione con un'inizializzazione valore-reale non avviene per nessun costruttore, ma invece verrà inizializzata in ritardo con un metodo o un'infrarenza di dipendenza.

Guardiamo un esempio per capire questo modificatore di proprietà univoco.

Nel codice di cui sopra abbiamo dichiarato una proprietà di repository mutable mutevole che è di tipo Repository all'interno del presentatore di classe e abbiamo quindi inizializzato questa proprietà a null durante la dichiarazione. Abbiamo un metodo initRepository () nella classe Presentatore che reinizializza questa proprietà in un secondo momento con un'istanza repositiva reale. Si noti che questa proprietà può anche essere assegnata a un valore utilizzando un iniettore di dipendenza come Dagger.

Ora per noi invocare metodi o proprietà su questa proprietà del repository, dobbiamo fare un controllo null o utilizzare l'operatore di chiamate di sicurezza. Perché? Poiché la proprietà del repository è di tipo nullable (Repository?). (Se avete bisogno di un rinfrescante per nullabilità a Kotlin, visita gentilmente Nullability, Loops e Condizioni).

Per evitare di eseguire controlli nulli ogni volta che abbiamo bisogno di invocare il metodo di una proprietà, possiamo contrassegnare questa proprietà con il modificatore del latteinsene. Ciò significa che abbiamo dichiarato che la proprietà (che è un'istanza di un'altra classe) come inizializzato in ritardo (cioè la proprietà verrà inizializzata in seguito).

Adesso, finché aspettiamo che la proprietà sia stata assegnata un valore, siamo sicuri di accedere ai metodi della proprietà senza eseguire controlli nulli. L'inizializzazione della proprietà può avvenire sia in un metodo setter che tramite l'iniezione di dipendenza.

Si noti che se si tenta di accedere ai metodi della proprietà, prima è stato inizializzato, avremo un kotlin. UninitializedPropertyAccessException invece di NullPointerException. In questo caso, il messaggio di eccezione sarà "repository di proprietà lateinit non è stato inizializzato".

Notare anche le seguenti restrizioni imposte quando ritarda l'inizializzazione di proprietà con i lateinit:

  • Deve essere mutevole (dichiarato con var).
  • Il tipo di proprietà non può essere un tipo primitivo, ad esempio Int, Double, Float e così via.
  • La proprietà non può avere un getter personalizzato o setter.

2. Proprietà in linea

Nelle funzioni avanzate, ho introdotto il modifier inline per funzioni di ordine superiore: questo aiuta a ottimizzare le funzioni di ordine superiore che accettano un lambda come parametro.

In Kotlin possiamo anche utilizzare questo modificatore in linea sulle proprietà. L'utilizzo di questo modificatore ottimizza l'accesso alla proprietà.

Vediamo un esempio pratico.

Nel codice precedente, abbiamo una proprietà normale, soprannome, che non presentano il modificatore inline. Se abbiamo decompilare il frammento di codice, utilizzando la funzionalità Visualizza Kotlin Bytecode (se siete in IntelliJ IDEA o Android Studio, utilizzare strumenti > Kotlin > Visualizza Kotlin Bytecode), vedremo il codice Java riportato di seguito:

Nel codice Java generato sopra (alcuni elementi del codice generato sono stati rimossi per brevità), si può vedere che, all'interno del metodo Main (), il compilatore ha creato un oggetto Student, chiamato il metodo getNickName() e quindi stampato il valore restituito.

Ora specifichiamo la proprietà come in linea e confrontiamo il codice di byte generato.

Basti inserire il modificatore in linea prima del modificatore di variabile: var o val. Ecco il codice bytecode generato per questa proprietà inline:

Ancora un certo codice è stato rimosso, ma la chiave da notare è il metodo principale (). Il compilatore ha copiato il corpo della funzione get () e incollato nel sito di chiamata (questo meccanismo è simile alle funzioni inline).

Il nostro codice è stato ottimizzato perché non è necessario creare un oggetto e chiamare il metodo getter proprietà. Ma, come discusso nelle funzioni di inline funzione, avremmo un bytecode più grande di prima - quindi utilizzare con cautela.

Notare anche che questo meccanismo funzionerà per le proprietà che non dispongono di un campo di backup (ricorda che un campo di backup è solo un campo utilizzato dalle proprietà quando si desidera modificare o utilizzare i dati di campo).

3. Proprietà estensione

Nelle funzioni avanzate ho anche discusso le funzioni di estensione — questi ci danno la possibilità di estendere una classe con nuove funzionalità senza dover ereditare da quella classe. Kotlin fornisce inoltre un meccanismo simile per proprietà, denominate proprietà di estensione.

Nel post funzioni avanzate abbiamo definito una funzione di estensione uppercaseFirstLetter() con tipo di ricevitore stringa. A questo punto, l'abbiamo convertita in una proprietà di estensione di livello superiore. Si noti che è necessario definire un metodo getter sulla proprietà per farlo funzionare.

Quindi, con questa nuova conoscenza delle proprietà di estensione, saprai che se hai mai desiderato che una classe avesse una proprietà che non fosse disponibile, puoi creare una proprietà di estensione di quella classe.

4. Classi di dati

Cominciamo con una tipica classe Java o POJO (Plain Old Java Object).

Come potete vedere, dobbiamo codificare in modo esplicito gli accessori delle proprietà di classe: i metodi getter e setter, nonché i metodi hashcode, uguali e toString (anche se IntelliJ IDEA, Android Studio o la libreria di AutoValue possono aiutarci a generarli). Vediamo questo tipo di codice di boilerplate principalmente nello strato di dati di un tipico progetto Java. (Ho rimosso gli accessoristi del campo e il costruttore per motivi di brevità).

La cosa cool è che il team di Kotlin ci ha fornito il modifier dei dati per le classi per eliminare la scrittura di questi boilerplate.

Ora scriviamo il codice precedente in Kotlin.

Eccezionale! Basta specificare il modificatore di dati prima della parola chiave di classe per creare una classe di dati, proprio come quello che abbiamo fatto nella nostra classe di BlogPost Kotlin sopra. Ora i metodi equal, hashcode, toString, copia e più componenti verranno creati sotto il cofano per noi. Si noti che una classe di dati può estendere altre classi (questa è una nuova caratteristica di Kotlin 1.1).

Il metodo uguale

Questo metodo confronta due oggetti per uguaglianza e restituisce true se sono altrimenti uguali o falsi. In altre parole, confronta se le due istanze di classe contengono gli stessi dati.

In Kotlin, utilizzando l'operatore di uguaglianza == chiamerà il metodo uguale dietro le quinte.

Il metodo hashCode

Questo metodo restituisce un valore intero utilizzato per la memorizzazione rapida e il recupero di dati memorizzati in una struttura di dati di raccolta basata su hash, ad esempio nei tipi di raccolta HashMap e HashSet.

Il metodo toString

Questo metodo restituisce una rappresentazione String di un oggetto.

Semplicemente chiamando l'istanza di classe, otterremo un oggetto di stringa restituito a noi - Kotlin chiama l'oggetto toString () sotto il cofano per noi. Ma se non mettiamo la parola chiave dei dati, vediamo quale sarà la rappresentazione della nostra stringa di oggetti:

Molto meno informativo!

Metodo di copia

Questo metodo ci consente di creare una nuova istanza di un oggetto con tutti gli stessi valori di proprietà. In altre parole, crea una copia dell'oggetto.

Una cosa cool circa il metodo di copia in Kotlin è la capacità di cambiare proprietà durante la copia.

Se sei un codificatore Java, questo metodo è simile al metodo clone () già conosciuto. Ma il metodo di copia Kotlin ha funzionalità più potenti.

Dichiarazione distruttiva

Nella classe Person, abbiamo anche due metodi generati automaticamente da noi dal compilatore a causa della parola chiave dei dati inserita nella classe. Questi due metodi sono prefisso con "componente", seguito da un suffisso numerico: component1 (), component2 (). Ognuno di questi metodi rappresenta le singole proprietà del tipo. Si noti che il suffisso corrisponde all'ordine delle proprietà dichiarate nel costruttore primario.

Quindi, nel nostro esempio chiamando component1 () restituirà il primo nome e chiamando component2 () restituirà il cognome.

Chiamare le proprietà utilizzando questo stile è difficile da capire e leggere, però, chiamando esplicitamente il nome della proprietà è molto meglio. Tuttavia, queste proprietà implicitamente create hanno uno scopo molto utile: ci fanno una dichiarazione di deformazione, in cui possiamo assegnare ciascun componente a una variabile locale.

Quello che abbiamo fatto qui è quello di assegnare rispettivamente le prime e le seconde proprietà (firstName e lastName) del tipo Persona alle variabili firstName e lastName rispettivamente. Ho anche discusso questo meccanismo noto come dichiarazione di destructuring nell'ultima sezione del pacchetto e Funzioni di base post.

5. Nidificate classi

Nella posta più divertente con funzioni, ti ho detto che Kotlin supporta funzioni locali o nidificate, una funzione che viene dichiarata all'interno di un'altra funzione. Beh, Kotlin supporta anche le classi nidificate, una classe creata all'interno di un'altra classe.

Chiamiamo anche le funzioni pubbliche della classe nidificata come di seguito riportato: una classe nidificata in Kotlin equivale a una classe nidificata statica in Java. Si noti che le classi nidificate non possono memorizzare un riferimento alla loro classe esterna.

Siamo anche liberi di impostare la classe nidificata come privata. Ciò significa che possiamo solo creare un'istanza del NestedClass nell'ambito dell'OuterClass.

Classe interna

Le classi interne, d'altra parte, possono fare riferimento la classe esterna che è stata dichiarata nel. Per creare una classe interna, abbiamo posto la parola chiave interna prima della parola chiave class in una classe nidificata.

Qui si fa riferimento la OuterClass dalla InnerClass utilizzando this@OuterClass.

6. Enumera classi

Un tipo enum dichiara un insieme di costanti rappresentato da identificatori. Questo speciale tipo di classe è creato dalla parola chiave enum specificato prima la parola chiave class.

Per recuperare un valore enum basato sul suo nome (proprio come in Java), facciamo questo:

O possiamo usare il enumValueOf Kotlin<T>() metodo di supporto per le costanti di accesso in modo generico:</T>

Inoltre, possiamo ottenere tutti i valori (come per un enum Java) come questo:

Infine, possiamo usare il enumValues Kotlin<T>() metodo di supporto per ottenere tutte le voci di enum in modo generico:</T>

Restituisce una matrice contenente le voci di enum.

Costruttori di enum

Proprio come una normale classe, il tipo enum può avere un proprio costruttore con proprietà associate a ciascuna costante di enum.

Nel costruttore paese enum tipo primario, abbiamo definito il callingCodes di proprietà non modificabili per ogni costante di enum. In ciascuna delle costanti, abbiamo passato un argomento al costruttore.

Possiamo quindi accedere la proprietà costanti come questo:

7. Classi sealed

Una classe sealed in Kotlin è una classe astratta (non si prevede di creare oggetti da esso), che possono estendere altre classi. Queste sottoclassi sono definite all'interno del corpo di classe sealed — nello stesso file. Perché tutte queste sottoclassi sono definite all'interno del corpo di classe sealed, possiamo sapere tutte le sottoclassi possibile semplicemente visualizzando il file.

Vediamo un esempio pratico.

Per dichiarare una classe come sealed, inseriamo il modificatore sealed prima il modificatore di classe nell'intestazione della dichiarazione di classe — nel nostro caso, abbiamo dichiarato la classe Shape come sealed. Una classe sealed è incompleta senza sue sottoclassi — proprio come una tipica classe astratta — quindi dobbiamo dichiarare le sottoclassi individuali all'interno del file stesso (shape.kt in questo caso). Si noti che non è possibile definire una sottoclasse di una classe sealed da un altro file.

Nel nostro codice di cui sopra, abbiamo specificato che la classe Shape può essere estesa solo dalle classi rettangolo, triangolo e cerchio.

Le classi sealed in Kotlin hanno le seguenti regole aggiuntive:

  • Possiamo aggiungere l'abstract di modificatore per una classe sealed, ma questo è ridondante perché le classi sealed sono astratte per impostazione predefinita.
  • Le classi sealed non possono avere il modificatore aperto o finale.
  • Siamo anche liberi di dichiarare classi di dati e oggetti come le sottoclassi di una classe sealed (hanno ancora bisogno di essere dichiarato nello stesso file).
  • Le classi sealed non possono avere costruttori pubblici — loro costruttori sono privati per impostazione predefinita.

Le classi che estendono le sottoclassi di una classe sealed possono essere posizionate nel file stesso o un altro file. La sottoclasse di classe sealed deve essere contrassegnato con il modificatore aperto (scoprirai ulteriori informazioni sull'ereditarietà in Kotlin nel prossimo post).

Una classe sealed e relative sottoclassi sono molto utili in una quando espressione. Per esempio:

Qui il compilatore è intelligente per garantire abbiamo coperto quando tutti i possibili casi. Ciò significa che non c'è nessuna necessità di aggiungere la clausola else.

Se dovessimo fare invece la seguente:

Il codice non compilato, perché non abbiamo incluso tutti i casi possibili. Avremmo il seguente errore:

Così abbiamo potuto includere il caso rettangolo o includere la clausola else per completare il quando espressione.

Conclusione

In questo tutorial, imparato di più su classi in Kotlin. Abbiamo coperto le seguenti informazioni sulle proprietà di classe:

  • inizializzazione di tardo
  • Proprietà inline
  • Proprietà di estensione

Inoltre, hai imparato alcune classi cool e avanzate quali dati, enum, annidati e classi sealed. Nel prossimo tutorial della serie Kotlin da zero, verrà introdotto per interfacce ed ereditarietà in Kotlin. A presto!

Per ulteriori informazioni sul linguaggio Kotlin, mi consiglia di visitare la documentazione di Kotlin. O Scopri alcuni dei nostri altri Android app sviluppo post qui su Envato Tuts!

Advertisement
Advertisement
Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.