Kotlin este un limbaj de programare modern care se compilează la Java bytecode. Este gratuit și open source, și promite să facă codificarea pentru Android chiar mai distractiv.
În articolul precedent, ați aflat despre clase și obiecte din Kotlin. În acest tutorial, vom continua să aflăm mai multe despre proprietăți și, de asemenea, să examinăm tipurile de cursuri avansate de la Kotlin, explorând următoarele:
Putem declara o proprietate non-null in Kotlin as târziu-inițializat. Aceasta înseamnă că o proprietate non-null nu va fi inițializată la momentul declarației, cu o inițializare valori-reale nu se va întâmpla prin nici un constructor - dar în schimb va fi întârziată inițializată printr-o metodă sau o injecție de dependență.
Să examinăm un exemplu pentru a înțelege acest modificator de proprietate unic.
clasa Presenter depozit privat var: Depozit? = null fun initRepository (repo: Repository): Unitatea this.repository = repo clasa Repository fun saveAmount (suma: Double)
În codul de mai sus, am declarat că nu poate fi mutat repertoriu
proprietate care este de tip Repertoriu
-în interiorul clasei Prezentator
-și am inițializat această proprietate la nulă în timpul declarației. Avem o metodă initRepository ()
în Prezentator
clasă care reinicializează mai târziu această proprietate cu o realitate Repertoriu
instanță. Rețineți că acestei proprietăți i se poate atribui o valoare utilizând un injector de dependență, cum ar fi Dagger.
Acum, pentru noi, să invocăm metode sau proprietăți în acest sens repertoriu
proprietate, trebuie să facem o verificare nulă sau să folosim operatorul de apel în condiții de siguranță. De ce? Deoarece repertoriu
proprietatea este de tip nullabil (Repertoriu?
). (Dacă aveți nevoie de o reîmprospătare a nulității în Kotlin, vă rugăm să vizitați Nullabilitate, Loops și condiții).
// Clasa Inside Presenter distracție salvați (suma: Dublă) repository? .SaveAmount (sumă)
Pentru a evita efectuarea de verificări null de fiecare dată când trebuie să invocăm o metodă a unei proprietăți, putem marca acea proprietate cu lateinit
modificator - aceasta înseamnă că am declarat că proprietatea (care este o instanță a unei alte clase) este târziu-inițializat (adică proprietatea va fi inițializată mai târziu).
clasă Presenter private lateinit var repository: Repository // ...
Acum, atâta timp cât așteptăm până când proprietatea a dat o valoare, suntem siguri să accesăm metodele proprietății fără a efectua nicio verificare nulă. Initializarea proprietății se poate realiza fie printr-o metodă de setare, fie prin injecție de dependență.
repository.saveAmount (suma)
Rețineți că dacă încercăm să accesăm metode ale proprietății înainte de a fi inițializată, vom obține o kotlin.UninitializedPropertyAccessException
în loc de un NullPointerException
. În acest caz, mesajul de excepție va fi "repositoarea de proprietăți de la sfârșitul anului nu a fost inițializată".
Rețineți și următoarele restricții la întârzierea inițializării unei proprietăți cu lateinit
:
var
).Int
, Dubla
, Pluti
, si asa mai departe. În funcțiile avansate, am introdus in linie
modificator pentru funcții de ordin superior - aceasta ajută la optimizarea oricăror funcții de ordin superior care acceptă o valoare lambda ca parametru.
În Kotlin, putem folosi și acest lucru in linie
modificator asupra proprietăților. Utilizarea acestui modificator va optimiza accesul la proprietate.
Să vedem un exemplu practic.
Class Student_value: String get () println ("Nick name retrieved") retur "koloCoder" fun main (args: Array) student val = Student () print (student.nickName)
În codul de mai sus, avem o proprietate normală, poreclă
, care nu are in linie
modificator. Dacă decomprimăm fragmentul de cod, folosiți Afișați Bytecode Kotlin (dacă vă aflați în IntelliJ IDEA sau Android Studio, utilizați Unelte > Kotlin > Afișați Bytecode Kotlin), vom vedea următorul cod Java:
clasa publica finala a studentilor @NotNull public final String getNickName () String var1 = "Numele nick-ului primit"; System.out.println (var1); retur "wheelCoder"; public clasa finală InlineFunctionKt public static final void principal (@NotNull String [] args) Intrinsics.checkParameterIsNotNull (args, "args"); Student student = student nou (); Stringul var2 = student.getNickName (); System.out.print (var2);
În codul Java generat de mai sus (unele elemente ale codului generat au fost eliminate pentru dragul brevetului), puteți vedea că în interiorul principal()
metoda pe care compilatorul a creat - o Student
obiect, numit getNickName ()
, apoi tipăriți valoarea returnată.
Să specificăm acum proprietatea ca in linie
în schimb, și comparați octetul generat.
// ... inline val nickName: String // ...
Introducem doar in linie
modificator înainte de modificatorul variabil: var
sau Val
. Iată octetul generat pentru această proprietate inline:
// ... static public final void principal (@NotNull String [] args) Intrinsics.checkParameterIsNotNull (args, "args"); Student student = student nou (); String var3 = "Numele de prenume recuperat"; System.out.println (var3); String var2 = "colocator"; System.out.print (var2); // ...
Din nou, un anumit cod a fost eliminat, dar cheia care trebuie luată în considerare este principal()
metodă. Compilatorul a copiat proprietatea obține()
funcția organism și lipit-o în site-ul de apel (acest mecanism este similar cu funcțiile inline).
Codul nostru a fost optimizat din cauza lipsei de a crea un obiect și de a apela metoda getter-ului. Dar, după cum sa discutat în postul de funcții inline, am avea un ocol mai mare decât înainte - deci folosiți cu prudență.
Rețineți, de asemenea, că acest mecanism va funcționa pentru proprietăți care nu au un câmp de asistență (rețineți că un câmp de asistență este doar un câmp care este utilizat de proprietăți atunci când doriți să modificați sau să utilizați acele date din câmp).
În funcțiile avansate am discutat, de asemenea, despre funcții de extensie - acestea ne dau posibilitatea de a extinde o clasă cu noi funcționalități fără a trebui să moștenim din acea clasă. Kotlin oferă, de asemenea, un mecanism similar pentru proprietăți, numit proprietăți de extindere.
val String.upperCaseFirstLetter: String get () = this.substring (0, 1) .toUpperCase () plus (this.substring (1))
În postul Advanced Functions am definit a uppercaseFirstLetter ()
funcția de extensie cu tipul receptorului Şir
. Aici am transformat-o într-o proprietate de extensie la cel mai înalt nivel. Rețineți că trebuie să definiți o metodă getter pe proprietatea dvs. pentru ca aceasta să funcționeze.
Prin urmare, cu aceste noi cunoștințe despre proprietățile de extensie, veți ști că, dacă doriți vreodată ca o clasă să aibă o proprietate care nu a fost disponibilă, aveți libertatea de a crea o proprietate de extindere a acelei clase.
Să începem cu o clasă Java tipică sau POJO (obiect obișnuit Java obișnuit).
clasă publică BlogPost final final String; adresa URL privată finală URI; descriere finală privată a șirului; finală privată Data publicăriiDate; // constructorul nu este inclus pentru brevetitate @Override public boolean equals (Object o) if (this == o) return true; dacă (o == null || getClass ()! = o.getClass ()) return false; BlogPost blogPost = (BlogPost) o; dacă (titlu! = null?! title.equals (blogPost.title): blogPost.title! = null) return false; dacă (url! = null?! url.equals (blogPost.url): blogPost.url! = null) return false; dacă descrierea! = null?! description.equals (blogPost.description): blogPost.description! = null) return false; retur publicDate! = null? publishDate.equals (blogPost.publishDate): blogPost.publishDate == null; @Overide public int hashCode () int rezultat = titlu! = Null? title.hashCode (): 0; rezultat = 31 * rezultat + (url! = null? url.hashCode (): 0); rezultat = 31 * rezultat + (descrierea! = null? description.hashCode (): 0); rezultatul = 31 * rezultat + (publishDate! = null? publishDate.hashCode (): 0); rezultatul retur; @Override public String toString () return "BlogPost " + "title = '+ + titlu +', + url + publishDate + ''; // ... setteri și getters, de asemenea, ignorați pentru dragul brevity
După cum puteți vedea, trebuie să codificăm în mod explicit accesoriile proprietății clasei: getter și setter, precum și hashCode
, este egală
, și toString
(deși IntelliJ IDEA, Android Studio sau biblioteca AutoValue ne poate ajuta să le generăm). Vom vedea acest tip de cod de boilerplate în cea mai mare parte în stratul de date al unui proiect tipic Java. (Am scos accesoriile de teren și constructorul pentru dragul lor).
Lucrul interesant este că echipa Kotlin ne-a oferit date
modifier pentru clasele de a elimina scrierea acestor boilerplate.
Să scriem acum codul precedent în Kotlin.
clasa de date BlogPost (titlul de var: String, var url: URI, var descriere: String, var publishDate: Data)
Minunat! Specificăm doar date
modificator înainte de clasă
cuvânt cheie pentru a crea o clasă de date - la fel ca și în ceea ce le-am făcut Postare pe blog
Clasa Kotlin de mai sus. Acum este egală
, hashCode
, toString
, copie
, și mai multe metode componente vor fi create sub capota pentru noi. Rețineți că o clasă de date poate extinde alte clase (aceasta este o caracteristică nouă a lui Kotlin 1.1).
este egală
MetodăAceastă metodă compară două obiecte pentru egalitate și returnează adevărat dacă sunt egale sau false altfel. Cu alte cuvinte, compară dacă cele două instanțe de clasă conțin aceleași date.
student.equals (student3) // folosind == în studentul Kotlin == student3 // același lucru ca folosind equals ()
În Kotlin, folosind operatorul de egalitate ==
va apela este egală
metoda din spatele scenei.
hashCode
Metodă Această metodă returnează o valoare intregă utilizată pentru stocarea rapidă și recuperarea datelor stocate într-o structură de date bazată pe hash, de exemplu în HashMap
și HashSet
tipuri de colecții.
toString
MetodăAceastă metodă returnează a Şir
reprezentarea unui obiect.
date personale (varName: String, var lastName: String) val person = Persoană ("Chike", "Mgbemena") println
Doar prin apelarea instanței de clasă, primim un obiect șir returnat la noi - Kotlin sună obiectul toString ()
sub capota pentru noi. Dar dacă nu punem date
cuvânt cheie în, a vedea ceea ce reprezentarea șir de obiect ar fi:
com.chike.kotlin.classes.Person@2f0e140b
Mult mai puțin informativ!
copie
MetodăAceastă metodă ne permite să creăm o nouă instanță a unui obiect cu toate aceleași valori de proprietate. Cu alte cuvinte, creează o copie a obiectului.
val person1 = Persoană ("Chike", "Mgbemena") println (person1) // Persoană (FirstName = Chike, lastName = Mgbemena) = Mgbemena)
Un lucru minunat despre copie
Metoda în Kotlin este abilitatea de a schimba proprietățile în timpul copierii.
val person3 = person1.copy (lastName = "Onu") println (person3) // Person3 (firstName = Chike, lastName = Onu)
Dacă sunteți coder Java, această metodă este similară cu cea de clona ()
cu care sunteți deja familiarizați. Dar Kotlin copie
metoda are caracteristici mai puternice.
În Persoană
clasa, avem, de asemenea, două metode generate automat de noi de către compilator din cauza date
cuvântul cheie plasat în clasă. Aceste două metode sunt prefixate cu "component", urmate de un sufix de număr: component1 ()
, component2 ()
. Fiecare dintre aceste metode reprezintă proprietățile individuale ale tipului. Rețineți că sufixul corespunde ordinii proprietăților declarate în constructorul principal.
Deci, în apelul nostru de exemplu component1 ()
va întoarce primul nume și va apela component2 ()
va returna numele de familie.
println (person3.component1 ()) // Chike println (person3.component2 ()) // Onu
Apelarea proprietăților utilizând acest stil este dificil de înțeles și de citit, însă apelarea explicit a numelui proprietății este mult mai bună. Cu toate acestea, aceste proprietăți create implicit au un scop foarte util: ne permit să facem o declarație de distrugere, în care putem atribui fiecare componentă unei variabile locale.
val (nume, prenume) = persoana ("Angelina", "Jolie") println (firstName + "" + lastName)
Ce am făcut aici este atribuirea directă a primelor și a doua proprietăți (Nume
și numele de familie
) din Persoană
tip la variabile Nume
și numele de familie
respectiv. Am discutat, de asemenea, acest mecanism cunoscut sub numele de declarație de distrugere în ultima secțiune a mesajului "Pachete și funcții de bază".
În postul Mai mult fun cu funcții, v-am spus că Kotlin are suport pentru funcții locale sau imbricate - o funcție declarată în interiorul unei alte funcții. Ei bine, Kotlin susține, de asemenea, în mod similar, clase imbricate - o clasă creată într-o altă clasă.
clasa OuterClass class NestedClass distracție nestedClassFunc ()
Apelăm chiar funcțiile publice ale clasei imbricate așa cum se vede mai jos - o clasă imbricată în Kotlin este echivalentă cu a static
clasa imbricata in Java. Rețineți că clasele imbricate nu pot stoca o referință la clasa lor exterioară.
val nestedClass = OuterClass.NestedClass () nestedClass.nestedClassFunc ()
De asemenea, suntem liberi să setăm clasa imbricată ca privată - aceasta înseamnă că putem crea doar o instanță a NestedClass
în cadrul domeniului OuterClass
.
Clasele interioare, pe de altă parte, pot face referire la clasa exterioară în care a fost declarată. Pentru a crea o clasă interioară, plasăm interior
cuvânt cheie înainte de clasă
cuvânt cheie într-o clasă imbricată.
clasa OuterClass () val oCPropt: String = "Yo" clasa interioara InnerClass fun interiorClassFunc () val exteriorClass = aceasta @ OuterClass print (outerClass.oCPropt) // imprimă "Yo"
Aici facem referire la OuterClass
de la InnerClass
prin utilizarea acest @ OuterClass
.
Un tip enum declară un set de constante reprezentate de identificatori. Acest tip special de clasă este creat de cuvântul cheie enum
care este specificat înainte de clasă
cuvinte cheie.
clasa enum Țara NIGERIA, GHANA, CANADA
Pentru a prelua o valoare enum pe baza numelui ei (la fel ca în Java), facem acest lucru:
Country.valueOf ( "NIGERIA")
Sau putem folosi Kotlin enumValueOf
metoda helper pentru a accesa constantele într-un mod generic:
enumValueOf("NIGERIA")
De asemenea, putem obține toate valorile (ca pentru un enum Java) astfel:
Country.values ()
În cele din urmă, putem folosi Kotlin EnumValues
metoda helper pentru a obține toate intrările enum într-un mod generic:
EnumValues()
Aceasta returnează o matrice care conține intrările enum.
La fel ca o clasă normală enum
tip poate avea propriul constructor cu proprietăți asociate fiecărei constante enum.
clasa enum Țara (val callingCode: Int) NIGERIA (234), SUA (1), GHANA (233)
În Țară
enum, am definit proprietatea imuabilă callingCodes
pentru fiecare constantă enum. În fiecare dintre constante, am dat un argument constructorului.
Putem apoi să accesăm proprietățile constante, astfel:
val țară = țara.NIGERIA print (country.callingCode) // 234
O clasă sigilată în Kotlin este o clasă abstractă (nu intenționați niciodată să creați obiecte din ea) pe care alte clase le pot extinde. Aceste subclase sunt definite în interiorul corpului clasei închise - în același fișier. Deoarece toate aceste subclase sunt definite în interiorul corpului de clasă închis, putem cunoaște toate subclasele posibile prin vizualizarea pur și simplu a fișierului.
Să vedem un exemplu practic.
// shape.kt clasă închisă Formă de formă Cerc: Formă de formă () Triunghi: Formă () clasă Dreptunghi: Formă ()
Pentru a declara o clasă ca fiind sigilată, inserăm sigilate
modificator înainte de clasă
modificator în antetul declarației de clasă - în cazul nostru, am declarat Formă
clasa ca sigilate
. O clasă sigilată este incompletă fără subclasele sale - la fel ca o clasă abstractă tipică - deci trebuie să declare subclasele individuale din același fișier (shape.kt în acest caz). Rețineți că nu puteți defini o subclasă a unei clase sigilate dintr-un alt fișier.
În codul de mai sus, am specificat că Formă
clasa poate fi extinsă doar de clase Cerc
, Triunghi
, și Dreptunghi
.
Clasele închise în Kotlin au următoarele reguli suplimentare:
abstract
la o clasă sigilată, dar acest lucru este redundant, deoarece clasele sigilate sunt în mod implicit abstracte.deschis
sau final
modificator. Clasele care extind subclasele unei clase închise pot fi plasate fie în același fișier, fie într-un alt fișier. Subclasa de clasă închisă trebuie marcată cu deschis
modificator (veți afla mai multe despre moștenire în Kotlin în postul următor).
// employee.kt clasa sigilată Angajat clasă deschisă Artist: Angajat () // class musician.kt Muzician: Artist ()
O clasă sigilată și subclasele sale sunt într-adevăr la îndemână cand
expresie. De exemplu:
distracție whatIsIt (formă: Shape) = atunci când (forma) este cerc -> println ("un cerc") este triunghi -> println ("triunghi"
Aici compilatorul este inteligent pentru a ne asigura că am acoperit toate posibilitățile cand
cazuri. Aceasta înseamnă că nu este nevoie să adăugați altfel
clauză.
Dacă ar fi trebuit să facem în schimb următoarele:
distracție whatIsIt (forma: Shape) = atunci când (forma) este cerc -> println ("un cerc") este triunghi -> println ("triunghi"
Codul nu s-ar compila, pentru că nu am inclus toate cazurile posibile. Am avea următoarea eroare:
Kotlin: expresia "atunci când" trebuie să fie exhaustivă, adăugați necesară o ramură dreptunghiulară sau o ramură "altceva".
Deci, am putea să includem și este dreptunghi
caz sau includeți altfel
clauză pentru a finaliza cand
expresie.
În acest tutorial, ați aflat mai multe despre cursurile din Kotlin. Am abordat următoarele despre proprietățile clasei:
De asemenea, ați învățat despre câteva clase cool și avansate, cum ar fi date, enum, imbricate și clase sigilate. În următorul tutorial din seria Kotlin From Scratch, veți fi introduși în interfețe și moștenire în Kotlin. Ne vedem în curând!
Pentru a afla mai multe despre limba Kotlin, vă recomand să vizitați documentația Kotlin. Sau verificați câteva dintre celelalte postări pentru dezvoltarea aplicațiilor Android aici pe Envato Tuts!