Kotlin er et moderne programmeringsspråk som kompilerer til Java bytecode. Det er gratis og åpen kildekode, og lover å gjøre koding for Android enda morsommere.
I den forrige artikkelen lærte du mer om Kotlin-egenskaper, for eksempel sentinitialisering, utvidelse og inline-egenskaper. Ikke bare det, du lærte også om avanserte klasser som data, enum, nestede og forseglede klasser i Kotlin.
I dette innlegget fortsetter du å lære om objektorientert programmering i Kotlin ved å lære om abstrakte klasser, grensesnitt og arv. For en bonus, vil du også lære om type aliaser.
Kotlin støtter abstrakte klasser - akkurat som Java, disse er klasser som du aldri har tenkt å lage objekter fra. En abstrakt klasse er ufullstendig eller ubrukelig uten noen konkrete (ikke-abstrakte) undergrupper, hvorfra du kan ordne objekter. En konkret underklasse av en abstrakt klasse implementerer alle metodene og egenskapene som er definert i abstrakt klassen ellers er underklassen også en abstrakt klasse!
Vi lager en abstrakt klasse med abstrakt
modifikator (ligner på Java).
abstrakt klasse Ansatt (val firstName: String, val lastName: String) abstrakt morsom inntjening (): Double
Merk at ikke alle medlemmer må være abstrakte. Med andre ord kan vi ha standard implementeringsmetode i en abstrakt klasse.
abstrakt klasse Medarbeider (val firstName: String, val lastName: String) // ... morsom fullName (): String return lastName + "" + firstName;
Her opprettet vi den ikke-abstrakte funksjonen fullt navn()
i en abstrakt klasse Ansatt
. Betongklasser (underklasser av abstrakt klasse) kan overstyre en abstrakt metode standard implementering - men bare hvis metoden har åpen
modifiserer spesifisert (du vil lære mer om dette innen kort tid).
Vi kan også lagre stat i abstrakte klasser.
abstrakt klasse Medarbeider (val firstName: String, val lastName: String) // ... val propFoo: String = "bla bla"
Selv om den abstrakte klassen ikke definerer noen metoder, må vi lage en underklasse før vi kan instantiere den, som i eksemplet nedenfor.
klassen programmerer (fornavn: streng, etternavn: streng): ansatt (fornavn, etternavn) overstyre morsom inntjening (): dobbelt // beregne inntekt
Våre Programmerer
klassen strekker seg ut Ansatt
abstrakt klasse. I Kotlin bruker vi en enkelt kolon karakter (:
) i stedet for Java strekker
søkeord for å utvide en klasse eller implementere et grensesnitt.
Vi kan da opprette et objekt av typen Programmerer
og samtale metoder på det-enten i sin egen klasse eller i superklassen (grunnklassen).
val programmerer = Programmerer ("Chike", "Mgbemena") println (programmerer.fullnavn ()) // "Mgbemena Chike"
En ting som kan overraske deg er at vi har muligheten til å overstyre a val
(uforanderlig) eiendom med Var
(Foranderlig).
open class BaseA (open val baseProp: String) klasse DerivedA: BaseA ("") private var derivedProp: String = "" overstyre var baseProp: String get () = derivedProp sett (verdi) derivedProp = value
Pass på at du bruker denne funksjonaliteten klokt! Vær oppmerksom på at vi ikke kan gjøre omvendt overstyring a Var
eiendom med val
.
Et grensesnitt er bare en samling av relaterte metoder som vanligvis lar deg fortelle objekter hva du skal gjøre og hvordan du gjør det som standard. (Standardmetoder i grensesnitt er en ny funksjon lagt til Java 8.) Med andre ord er et grensesnitt en kontrakt som implementerer klasser må overholde.
Et grensesnitt er definert ved hjelp av grensesnitt
søkeord i Kotlin (lik Java).
klasse Resultat klasse Student grensesnitt StudentRepository morsomt getById (id: Lang): Student moro getResultsById (id: Lang): Liste
I koden ovenfor har vi erklært en StudentRepository
grensesnitt. Dette grensesnittet inneholder to abstrakte metoder: getById ()
og getResultsById ()
. Legg merke til at inkludert abstrakt
Søkeordet er overflødig i en grensesnittmetode fordi de allerede er abstrakte implisitt.
Et grensesnitt er ubrukelig uten en eller flere implementatorer, så la oss lage en klasse som vil implementere dette grensesnittet.
klasse StudentLocalDataSource: StudentRepository overstyre morsomme getResults (id: Long): List// gjør implementering overstyre morsomt getById (id: Lang): Student // gjør implementering
Her opprettet vi en klasse StudentLocalDataSource
som implementerer StudentRepository
grensesnitt.
Vi bruker overstyring
modifikator for å merke metoder og egenskaper vi vil omdefinere fra grensesnittet eller superklasse - dette ligner på @Overstyring
annotasjon i Java.
Legg merke til følgende tilleggsregler for grensesnitt i Kotlin:
overstyring
Modifikator er obligatorisk i Kotlin-i motsetning til Java. La oss se et eksempel på en grensesnittmetode med standard implementering.
grensesnitt StudentRepository // ... morsomt slett (student: Student) // gjør implementering
I den forrige koden la vi til en ny metode delete ()
med en standard implementering (selv om jeg ikke la til den faktiske implementeringskoden for demonstrasjonsformål).
Vi har også friheten til å overstyre standard implementeringen hvis vi vil.
klasse StudentLocalDataSource: StudentRepository // ... override fun delete (student: Student) // gjør implementering
Som nevnt kan et Kotlin-grensesnitt ha egenskaper - men vær oppmerksom på at den ikke kan opprettholde tilstanden. (Men husk abstrakte klasser kan opprettholde tilstand.) Så følgende grensesnittdefinisjon med en eiendomserklæring vil fungere.
grensesnitt StudentRepository val propFoo: Boolean // vil fungere // ...
Men hvis vi prøver å legge til noen tilstand i grensesnittet ved å tilordne en verdi til eiendommen, vil det ikke fungere.
grensesnitt StudentRepository val propFoo: Boolean = true // Feil: Eiendomsinitialiser er ikke tillatt i grensesnitt // ...
Men en grensesnitt eiendom i Kotlin kan ha getter og setter metoder (men bare sistnevnte hvis eiendommen er mutable). Merk også at egenskapen i et grensesnitt ikke kan ha et bakre felt.
grensesnitt StudentRepository var propFoo: Boolean get () = true set (verdi) hvis (verdi) // gjør noe // ...
Vi kan også overstyre en grensesnittegenskap hvis du vil, for å omdefinere den.
klasse StudentLocalDataSource: StudentRepository // ... overstyre var propFoo: Boolean get () = false set (verdi) if (value)
La oss se på et tilfelle der vi har en klasse som implementerer flere grensesnitt med samme metodesignatur. Hvordan bestemmer klassen hvilken grensesnittsmetode som skal ringes?
grensesnitt InterfaceA morsomt funD () grensesnitt InterfaceB morsomt funD ()
Her har vi to grensesnitt som har en metode med samme signatur fond()
. La oss lage en klasse som implementerer disse to grensesnittene og overstyrer fond()
metode.
klasse klasseA: InterfaceA, InterfaceB override fun funD () super.funD () // Feil: Mange supertyper tilgjengelig, vennligst spesifiser det du mener i vinkelbeslag, f.eks. 'super'
Kompilatoren er forvirret om å ringe super.funD ()
metode fordi de to grensesnittene som klassen implementerer har samme metode signatur.
For å løse dette problemet, pakker vi grensesnittnavnet som vi ønsker å kalle metoden i vinkelbeslag
. (IntelliJ IDEA eller Android Studio vil gi deg et hint om å løse dette problemet når det avles.)
klasseklasseA: InterfaceA, InterfaceB override fun funD () super.funD ()
Her skal vi ringe fond()
Metode av InterfaceA
. Problemet løst!
En ny klasse (underklasse) er opprettet ved å anskaffe en eksisterende klasses (superklass) medlemmer og kanskje omdefinere sin standard implementering. Denne mekanismen er kjent som arv i objektorientert programmering (OOP). En av de tingene som gjør Kotlin så fantastisk er at den omfatter både OOP og funksjonelle programmeringsparadigmer - alt på ett språk.
Baseklassen for alle klasser i Kotlin er Noen
.
klasse Person: Enhver
De Noen
type er ekvivalent med Gjenstand
type vi har i Java.
offentlig åpen klasse Enhver offentlig åpen operatør moro er lik (andre: noen?): Boolean offentlig åpen moro hashCode (): Int offentlig åpen moro åString (): String
De Noen
Type inneholder følgende medlemmer: er lik()
, hashkode ()
, og også toString ()
metoder (som ligner på Java).
Våre klasser trenger ikke å eksplisitt utvide denne typen. Hvis du ikke spesifikt angir hvilken klasse en ny klasse utvider, strekker klassen ut Noen
implisitt. Av denne grunn trenger du vanligvis ikke å inkludere : Enhver
i koden-vi gjør det i koden ovenfor for demonstrasjonsformål.
La oss nå se på å lage klasser i Kotlin med arv i tankene.
klasse Student klasse GraduateStudent: Student ()
I koden ovenfor er Utdannet student
klassen utvider superklassen Student
. Men denne koden vil ikke kompilere. Hvorfor? Fordi klasser og metoder er endelig
som standard i Kotlin. Med andre ord kan de ikke utvides som standard - i motsetning til Java der klasser og metoder er åpne som standard.
Programvareteknikk beste praksis anbefaler at du begynner å lage dine klasser og metoder endelig
som standard-ie.e. hvis de ikke er spesielt ment å bli omdefinert eller overstyrt i underklasser. Kotlin-teamet (JetBrains) brukte denne kodingsfilosofien og mange flere utviklingsmetoder for å utvikle dette moderne språket.
For at vi skal kunne lage undergrupper fra en superklasse, må vi eksplisitt merke superklassen med åpen
modifier. Denne modifikatoren gjelder også for enhver superklasse eiendom eller metode som skal overstyres av underklasser.
åpen klasse student
Vi satte ganske enkelt åpen
modifikator før klasse
søkeord. Vi har nå instruert kompilatoren til å tillate vår Student
klasse for å være åpen for forlengelse.
Som nevnt tidligere er medlemmer av en Kotlin-klasse også endelige som standard.
åpen klasse Student open fun schoolFees (): BigDecimal // gjør implementering
I den forrige koden merket vi Skole utgifter
fungere som åpen
-slik at underklasser kan overstyre det.
åpen klasse GraduateStudent: Student () override fun schoolFees (): BigDecimal return super.schoolFees () + calculateSchoolFees () privat sjel calculateSchoolFees (): BigDecimal // regne og returnere skoleavgifter
Her er det åpent Skole utgifter
Funksjon fra superklassen Student
er overstyrt av Utdannet student
klasse - ved å legge til overstyring
modifikator før moro
søkeord. Merk at hvis du overstyrer et medlem av en superklasse eller et grensesnitt, vil det overordnede medlemmet også være åpen
som standard, som i eksemplet nedenfor:
klasse ComputerScienceStudent: GraduateStudent () override fun schoolFees (): BigDecimal return super.schoolFees () + calculateSchoolFess () privat sjel calculateSchoolFess (): BigDecimal // beregne og returnere skoleavgift
Selv om vi ikke markerte Skole utgifter()
metode i Utdannet student
klasse med åpen
modifikator, kan vi fortsatt overstyre det - som vi gjorde i ComputerScienceStudent
klasse. For å forhindre dette må vi markere det overordnede medlemmet som endelig
.
Husk at vi kan legge til ny funksjonalitet i en klasse - selv om den er endelig - ved hjelp av utvidelsesfunksjoner i Kotlin. For en oppdatering på utvidelsesfunksjoner, sjekk ut mine avanserte funksjoner i Kotlin-innlegget. Også, hvis du trenger en oppdatering på hvordan du gir enda en klasse nye egenskaper uten å arve fra det, les avsnittet om utvidelsesegenskaper i mine avanserte egenskaper og klasser etter.
Hvis vår superklasse har en primærkonstruent som dette:
åpen klasse Student (val firstName: String, val lastName: String) // ...
Deretter må noen underklasse ringe til den primære konstruktøren til superklassen.
åpen klasse GraduateStudent (firstName: String, LastName: String): Student (firstName, LastName) // ...
Vi kan bare lage et objekt av Utdannet student
klassen som vanlig:
val graduateStudent = GraduateStudent ("Jon", "Snow") println (graduateStudent.firstName) // Jon
Hvis underklassen ønsker å ringe superklassekonstruktøren fra sin sekundære konstruktør, bruker vi super
søkeord (ligner hvordan superklasse-konstruktører påberopes i Java).
åpen klasse GraduateStudent: Student // ... privat oppgave: String = "" konstruktør (firstName: String, LastName: String, avhandling: String): super (firstName, lastName) this.thesis = thesis
Hvis du trenger en oppfriskning på klassekonstruksjonene i Kotlin, vennligst besøk min klasse og objekter innlegg.
En annen fantastisk ting vi kan gjøre i Kotlin er å gi en type et alias.
La oss se et eksempel.
dataklasse Person (val firstName: String, val lastName: String, val alder: Int)
I klassen over kan vi tildele string
og int
typer for Person
egenskaper aliaser ved hjelp av typealias
modifikator i Kotlin. Denne modifikatoren brukes til å lage et alias av enhver type i Kotlin-inkludert de du har opprettet.
typealias Navn = String typealias Alder = Int dataklasse Person (val firstName: Navn, val sistnavn: Navn, val alder: Alder)
Som du kan se, har vi opprettet et alias Navn
og Alder
for begge string
og int
typer henholdsvis. Vi har nå erstattet fornavn
og etternavn
Eiendomstype til vårt alias Navn
-og også int
skriv til Alder
alias. Vær oppmerksom på at vi ikke opprettet nye typer, men i stedet opprettet et alias for typene.
Disse kan være nyttige når du vil gi en bedre mening eller semantikk til typer i Kotlin kodebase. Så bruk dem klokt!
I denne opplæringen lærte du mer om objektorientert programmering i Kotlin. Vi dekket følgende:
Hvis du har lært Kotlin gjennom vår Kotlin From Scratch-serie, må du kontrollere at du har skrevet koden du ser og kjører den på IDE. Et godt tips for å virkelig forstå et nytt programmeringsspråk (eller et hvilket som helst programmeringsbegrep) du lærer, er å sørge for at du ikke bare bare leser læringsressursen eller veiledningen, men skriver også selve koden og kjører den!
I neste opplæring i Kotlin From Scratch-serien blir du introdusert for unntakshåndtering i Kotlin. Ser deg snart!
For å lære mer om Kotlin-språket, anbefaler jeg at du besøker Kotlin-dokumentasjonen. Eller sjekk ut noen av våre andre Android-apputviklingsposter her på Envato Tuts!