Kotlin è un linguaggio di programmazione moderno che viene compilato in bytecode Java. È gratuito e open source e promette di rendere la codifica per Android ancora più divertente.
Nell'articolo precedente, hai imparato di più sulle proprietà di Kotlin come l'inizializzazione tardiva, l'estensione e le proprietà in linea. Non solo, hai anche imparato a conoscere classi avanzate come dati, enum, classi nidificate e sigillate in Kotlin.
In questo post, continuerai a conoscere la programmazione orientata agli oggetti in Kotlin imparando a conoscere classi, interfacce ed eredità astratte. Per un bonus, imparerai anche sugli alias dei tipi.
Kotlin supporta classi astratte, proprio come Java, sono classi da cui non si intende mai creare oggetti. Una classe astratta è incompleta o inutile senza alcune sottoclassi concrete (non astratte), dalle quali è possibile creare un'istanza di oggetti. Una sottoclasse concreta di una classe astratta implementa tutti i metodi e le proprietà definiti nella classe astratta, altrimenti quella sottoclasse è anche una classe astratta!
Creiamo una classe astratta con il astratto
modificatore (simile a Java).
abstract class Employee (val firstName: String, val lastName: String) abstract fun earnings (): Double
Nota che non tutti i membri devono essere astratti. In altre parole, possiamo avere un'implementazione predefinita del metodo in una classe astratta.
abstract class Employee (val firstName: String, val lastName: String) // ... fun fullName (): String return lastName + "" + firstName;
Qui abbiamo creato la funzione non astratta nome e cognome()
in una classe astratta Dipendente
. Le classi concrete (sottoclassi della classe astratta) possono sovrascrivere l'implementazione predefinita di un metodo astratto, ma solo se il metodo ha il Aperto
modificatore specificato (imparerai di più su questo a breve).
Possiamo anche memorizzare lo stato in classi astratte.
abstract class Employee (val firstName: String, val lastName: String) // ... val propFoo: String = "bla bla"
Anche se la classe astratta non definisce alcun metodo, dobbiamo creare una sottoclasse prima di poterla istanziare, come nell'esempio seguente.
class Programmer (firstName: String, lastName: String): Employee (firstName, lastName) override fun earnings (): Double // calcola guadagni
Nostro Programmatore
la classe estende il Dipendente
classe astratta. In Kotlin usiamo un singolo carattere del colon (:
) invece di Java si estende
parola chiave per estendere una classe o implementare un'interfaccia.
Possiamo quindi creare un oggetto di tipo Programmatore
e chiama i metodi su di esso - sia nella sua classe che nella superclasse (classe base).
val programmer = Programmer ("Chike", "Mgbemena") println (programmer.fullName ()) // "Mgbemena Chike"
Una cosa che potrebbe sorprendervi è che abbiamo la possibilità di ignorare a val
(immutabile) proprietà con var
(mutevole).
open class BaseA (open val baseProp: String) class DerivedA: BaseA ("") private var derivedProp: String = "" override var baseProp: String get () = derivedProp set (valore) derivedProp = valore
Assicurati di utilizzare questa funzionalità con saggezza! Tieni presente che non possiamo eseguire l'inversione di tendenza a var
immobili con val
.
Un'interfaccia è semplicemente una raccolta di metodi correlati che in genere ti consentono di dire agli oggetti cosa fare e anche come farlo di default. (I metodi predefiniti nelle interfacce sono una nuova funzionalità aggiunta a Java 8.) In altre parole, un'interfaccia è un contratto che le classi di implementazione devono rispettare.
Un'interfaccia è definita usando il interfaccia
parola chiave in Kotlin (simile a Java).
classe Classe risultato Interfaccia studente StudentRepository fun getById (id: Long): Student fun getResultsById (id: Long): List
Nel codice sopra, abbiamo dichiarato a StudentRepository
interfaccia. Questa interfaccia contiene due metodi astratti: getById ()
e getResultsById ()
. Si noti che incluso il astratto
la parola chiave è ridondante in un metodo di interfaccia perché sono già astrattamente implicitamente.
Un'interfaccia è inutile senza uno o più implementatori, quindi creiamo una classe che implementerà questa interfaccia.
class StudentLocalDataSource: StudentRepository override fun getResults (id: Long): List// do implementation sostituisce fun getById (id: Long): Student // do implementation
Qui abbiamo creato una classe StudentLocalDataSource
che implementa il StudentRepository
interfaccia.
Noi usiamo il oltrepassare
modificatore per etichettare i metodi e le proprietà che vogliamo ridefinire dall'interfaccia o dalla superclasse - questo è simile al @Oltrepassare
annotazione in Java.
Nota le seguenti regole aggiuntive di interfacce in Kotlin:
oltrepassare
il modificatore è obbligatorio in Kotlin, diversamente da Java. Vediamo un esempio di un metodo di interfaccia con un'implementazione predefinita.
interface StudentRepository // ... fun delete (studente: studente) // do implementation
Nel codice precedente, abbiamo aggiunto un nuovo metodo Elimina()
con un'implementazione predefinita (sebbene non abbia aggiunto il codice di implementazione effettivo a scopo dimostrativo).
Abbiamo anche la libertà di ignorare l'implementazione predefinita, se vogliamo.
class StudentLocalDataSource: StudentRepository // ... override fun delete (studente: Studente) // do implementation
Come affermato, un'interfaccia di Kotlin può avere proprietà, ma si noti che non può mantenere lo stato. (Tuttavia, ricorda che le classi astratte possono mantenere lo stato). Pertanto, la seguente definizione di interfaccia con una dichiarazione di proprietà funzionerà.
interface StudentRepository val propFoo: Boolean // funzionerà // ...
Ma se proviamo ad aggiungere qualche stato all'interfaccia assegnando un valore alla proprietà, non funzionerà.
interface StudentRepository val propFoo: Boolean = true // Errore: gli inizializzatori di proprietà non sono consentiti nelle interfacce // ...
Tuttavia, una proprietà di interfaccia in Kotlin può avere metodi getter e setter (sebbene solo quest'ultimo se la proprietà è mutabile). Si noti inoltre che la proprietà in un'interfaccia non può avere un campo di supporto.
interface StudentRepository var propFoo: Boolean get () = true set (valore) if (valore) // fa qualcosa // ...
Possiamo anche sostituire una proprietà dell'interfaccia se lo desideri, in modo da ridefinirlo.
class StudentLocalDataSource: StudentRepository // ... override var propFoo: Boolean get () = false set (valore) if (valore)
Diamo un'occhiata a un caso in cui abbiamo una classe che implementa più interfacce con la stessa firma del metodo. In che modo la classe decide quale metodo di interfaccia chiamare?
interface InterfaceA fun funD () interface InterfaceB fun funD ()
Qui abbiamo due interfacce che hanno un metodo con la stessa firma fondo()
. Creiamo una classe che implementa queste due interfacce e sovrascrive il fondo()
metodo.
classe classA: InterfaceA, InterfaceB override fun funD () super.funD () // Errore: molti supertipi disponibili, si prega di specificare quello che intendi in parentesi angolari, ad es. 'super'
Il compilatore è confuso sulla chiamata di super.funD ()
metodo perché le due interfacce che le implementazioni di classe hanno la stessa firma di metodo.
Per risolvere questo problema, avvolgiamo il nome dell'interfaccia per il quale vogliamo chiamare il metodo tra parentesi angolari
. (IntelliJ IDEA o Android Studio ti daranno un suggerimento su come risolvere questo problema quando emergerà.)
class classA: InterfaceA, InterfaceB override fun funD () super.funD ()
Qui chiameremo il fondo()
metodo di InterfaceA
. Problema risolto!
Una nuova classe (sottoclasse) viene creata acquisendo membri di una classe esistente (superclasse) e forse ridefinendo la loro implementazione predefinita. Questo meccanismo è noto come eredità in programmazione orientata agli oggetti (OOP). Una delle cose che rendono Kotlin così impressionante è che comprende sia i paradigmi di programmazione funzionale e OOP - tutti in una lingua.
La classe base per tutte le classi in Kotlin è Qualunque
.
classe Persona: Qualsiasi
Il Qualunque
il tipo è equivalente al Oggetto
tipo che abbiamo in Java.
public open class Qualsiasi public open operator fun uguale a (altro: Any?): Booleano public open fun hashCode (): Int public open fun toString (): String
Il Qualunque
tipo contiene i seguenti membri: è uguale a()
, codice hash()
, e anche accordare()
metodi (simili a Java).
Le nostre classi non hanno bisogno di estendere esplicitamente questo tipo. Se non si specifica esplicitamente in quale classe si estende una nuova classe, la classe si estende Qualunque
implicitamente. Per questo motivo, in genere non è necessario includere : Qualunque
nel tuo codice, lo facciamo nel codice sopra a scopo dimostrativo.
Diamo ora un'occhiata alla creazione di classi in Kotlin con l'ereditarietà in mente.
classe Studente classe LaureatoStudente: Studente ()
Nel codice sopra, il Studente laureato
la classe estende la superclasse Alunno
. Ma questo codice non verrà compilato. Perché? Perché le classi e i metodi sono finale
di default in Kotlin. In altre parole, non possono essere estesi per impostazione predefinita, diversamente da Java, dove classi e metodi sono aperti per impostazione predefinita.
Le migliori pratiche di ingegneria del software consigliano di iniziare a creare classi e metodi finale
di default-i.e. se non sono specificatamente destinati a essere ridefiniti o sovrascritti in sottoclassi. Il team di Kotlin (JetBrains) ha applicato questa filosofia di codifica e molte altre migliori pratiche di sviluppo nello sviluppo di questo linguaggio moderno.
Per consentire alle sottoclassi di essere create da una superclasse, dobbiamo contrassegnare esplicitamente la superclasse con la Aperto
modificatore. Questo modificatore si applica anche a qualsiasi proprietà o metodo di superclasse che dovrebbe essere sovrascritto dalle sottoclassi.
open class Student
Abbiamo semplicemente messo il Aperto
modificatore prima del classe
parola chiave. Ora abbiamo incaricato il compilatore di consentire il nostro Alunno
classe da aprire per l'estensione.
Come affermato in precedenza, i membri di una classe Kotlin sono anche definitivi per impostazione predefinita.
open class Studente open fun schoolFees (): BigDecimal // do implementation
Nel codice precedente, abbiamo contrassegnato il tasse scolastiche
funziona come Aperto
-in modo che le sottoclassi possano sovrascriverlo.
open class GraduateStudent: Student () override fun SchoolFees (): BigDecimal return super.schoolFees () + calculateSchoolFees () fun private calculateSchoolFees (): BigDecimal // calcola e restituisci tasse scolastiche
Qui, l'aperto tasse scolastiche
funzione dalla superclasse Alunno
è sovrascritto da Studente laureato
class-by aggiungendo il oltrepassare
modificatore prima del divertimento
parola chiave. Notare che se si sostituisce un membro di una superclasse o di un'interfaccia, lo sarà anche il membro che esegue l'override Aperto
per impostazione predefinita, come nell'esempio seguente:
class ComputerScienceStudent: GraduateStudent () override fun schoolFees (): BigDecimal return super.schoolFees () + calculateSchoolFess () fun private calculateSchoolFess (): BigDecimal // calcola e restituisci tasse scolastiche
Anche se non abbiamo segnato il tasse scolastiche()
metodo nel Studente laureato
classe con il Aperto
modificatore, possiamo ancora sovrascriverlo, come abbiamo fatto nel ComputerScienceStudent
classe. Per impedirlo, dobbiamo contrassegnare il membro preponderante come finale
.
Ricorda che possiamo aggiungere nuove funzionalità a una classe, anche se definitiva, utilizzando le funzioni di estensione in Kotlin. Per un aggiornamento sulle funzioni di estensione, controlla le mie funzioni avanzate nel post di Kotlin. Inoltre, se hai bisogno di un aggiornamento su come dare anche a una classe finale nuove proprietà senza ereditarne, leggi la sezione sulle proprietà dell'estensione nel mio post Advanced Properties and Classes.
Se la nostra superclasse ha un costruttore principale come questo:
open class Student (val firstName: String, val lastName: String) // ...
Quindi qualsiasi sottoclasse deve chiamare il costruttore principale della superclasse.
open class GraduateStudent (firstName: String, lastName: String): Student (firstName, lastName) // ...
Possiamo semplicemente creare un oggetto di Studente laureato
classe come al solito:
val graduateStudent = GraduateStudent ("Jon", "Snow") println (graduateStudent.firstName) // Jon
Se la sottoclasse desidera chiamare il costruttore della superclasse dal suo costruttore secondario, usiamo il super
parola chiave (simile a come i costruttori di superclasse vengono richiamati in Java).
open class GraduateStudent: Student // ... private var thesis: String = "" costruttore (firstName: String, lastName: String, thesis: String): super (firstName, lastName) this.thesis = thesis
Se hai bisogno di un aggiornamento sui costruttori di classi in Kotlin, visita gentilmente il mio post su Classi e Oggetti.
Un'altra cosa fantastica che possiamo fare in Kotlin è dare un alias al tipo.
Vediamo un esempio.
classe di dati Persona (val firstName: String, val lastName: String, val age: Int)
Nella classe sopra, possiamo assegnare il Stringa
e Int
tipi per il Persona
proprietà alias utilizzando il typealias
modificatore in Kotlin. Questo modificatore è usato per creare un alias di qualsiasi tipo in Kotlin, inclusi quelli che hai creato.
typealias Name = String typealias Age = Int classe dati Person (val firstName: Name, val lastName: Name, val age: Age)
Come puoi vedere, abbiamo creato un alias Nome
e Età
per entrambi Stringa
e Int
tipi rispettivamente. Ora abbiamo sostituito il nome di battesimo
e cognome
tipo di proprietà al nostro alias Nome
-e anche Int
digitare a Età
alias. Nota che non abbiamo creato nuovi tipi: abbiamo invece creato un alias per i tipi.
Questi possono essere utili quando si desidera fornire un significato migliore o tipi semantici al proprio codice Kotlin. Quindi usali saggiamente!
In questo tutorial, hai imparato di più sulla programmazione orientata agli oggetti in Kotlin. Abbiamo coperto quanto segue:
Se hai imparato Kotlin attraverso la nostra serie Kotlin From Scratch, assicurati di aver digitato il codice che vedi e di averlo eseguito sul tuo IDE. Un ottimo consiglio per comprendere davvero un nuovo linguaggio di programmazione (o qualsiasi altro concetto di programmazione) che stai imparando è quello di assicurarti di non solo leggere la guida o la risorsa di apprendimento, ma anche di digitare il codice reale ed eseguirlo!
Nel prossimo tutorial della serie Kotlin From Scratch, ti verrà presentata la gestione delle eccezioni in Kotlin. A presto!
Per saperne di più sulla lingua di Kotlin, ti consiglio di visitare la documentazione di Kotlin. Oppure guarda alcuni dei nostri altri post di sviluppo di app per Android qui su Envato Tuts!