Kotlin är ett modernt programmeringsspråk som kompilerar till Java bytecode. Det är gratis och öppen källkod, och lovar att göra kodning för Android ännu roligare.
I den föregående artikeln lärde du dig mer om Kotlin-egenskaper, såsom seninitiering, utvidgning och inline-egenskaper. Inte bara det, du lärde dig också om avancerade klasser som data, enum, nestad och förseglad klass i Kotlin.
I det här inlägget fortsätter du att lära dig om objektorienterad programmering i Kotlin genom att lära sig abstrakta klasser, gränssnitt och arv. För en bonus kommer du också att lära dig om typ alias.
Kotlin stöder abstrakta klasser, precis som Java, det här är klasser som du aldrig tänker skapa objekt från. En abstrakt klass är ofullständig eller användbar utan några konkreta (icke-abstrakta) underklasser, från vilka du kan instansera objekt. En konkret underklass av en abstrakt klass implementerar alla metoder och egenskaper som definieras i abstrakt klass - annars är denna underklass också en abstrakt klass!
Vi skapar en abstrakt klass med abstrakt
modifierare (liknande Java).
abstrakt klass Medarbetare (val firstName: String, val lastName: String) abstrakt roligt resultat (): Double
Observera att inte alla medlemmar måste vara abstrakta. Med andra ord kan vi ha metodinställningar i en abstrakt klass.
abstrakt klass Medarbetare (val firstName: String, val lastName: String) // ... rolig fullnamn (): String return lastName + "" + firstName;
Här skapade vi den icke-abstrakta funktionen fullständiga namn()
i en abstrakt klass Anställd
. Betongklasser (abclassklassens underklasser) kan överskrida en abstrakt metods standardimplementering - men endast om metoden har öppna
modifierare specificerad (du kommer lära dig mer om detta inom kort).
Vi kan också lagra stat i abstrakta klasser.
abstrakt klass Medarbetare (val firstName: String, val lastName: String) // ... val propFoo: String = "bla bla"
Även om den abstrakta klassen inte definierar några metoder måste vi skapa en underklass innan vi kan ordna det, som i exemplet nedan.
Programmerare (firstName: String, LastName: String): Anställd (förnamn, efternamn) överträffa roligt resultat (): Dubbel // beräkna resultat
Vår Programmerare
klassen sträcker sig Anställd
abstrakt klass. I Kotlin använder vi en enda kolon tecken (:
) istället för Java sträcker
sökord för att utöka en klass eller implementera ett gränssnitt.
Vi kan då skapa ett objekt av typen Programmerare
och kalla metoder på det - antingen i sin egen klass eller i superklassen (basklassen).
val programmerare = Programmerare ("Chike", "Mgbemena") println (programmerare.fullName ()) // "Mgbemena Chike"
En sak som kan överraska dig är att vi har förmåga att åsidosätta en val
(oföränderlig) egendom med var
(föränderlig).
öppna klass BaseA (öppen valbasProp: String) klass DerivedA: BaseA ("") privat var härleddProp: String = "" åsidosätt var basProp: String get () = derivedProp set (value) derivedProp = value
Se till att du använder den här funktionen klokt! Var medveten om att vi inte kan göra omvänd åsidosätt a var
egenskap med val
.
Ett gränssnitt är helt enkelt en samling relaterade metoder som vanligtvis gör att du kan berätta för objekt vad du ska göra och hur du gör det som standard. (Standardmetoder i gränssnitt är en ny funktion som läggs till i Java 8.) Med andra ord är ett gränssnitt ett kontrakt som implementeringsklasser måste följa.
Ett gränssnitt definieras med hjälp av gränssnitt
sökord i Kotlin (liknande Java).
klass Resultat klass Studentgränssnitt StudentRepository roligt getById (id: Långt): Student roligt getResultsById (id: Långt): Lista
I koden ovan har vi förklarat en StudentRepository
gränssnitt. Detta gränssnitt innehåller två abstrakta metoder: getById ()
och getResultsById ()
. Notera att inklusive abstrakt
sökordet är överflödigt i en gränssnittsmetod eftersom de redan är abstrakta implicit.
Ett gränssnitt är värdelöst utan en eller flera implementatörer-så låt oss skapa en klass som implementerar detta gränssnitt.
klass StudentLocalDataSource: StudentRepository överträffa roliga getResults (id: Long): List// gör implementation åsidosätta fun getById (id: Long): Student // implementering
Här skapade vi en klass StudentLocalDataSource
som implementerar StudentRepository
gränssnitt.
Vi använder åsidosätta
modifier för att märka de metoder och egenskaper vi vill omdefiniera från gränssnittet eller superklassen - det här liknar @Åsidosätta
annotering i Java.
Observera följande tilläggsregler för gränssnitt i Kotlin:
åsidosätta
Modifieraren är obligatorisk i Kotlin-till skillnad från Java. Låt oss se ett exempel på en gränssnittsmetod med en standardimplementering.
gränssnitt StudentRepository // ... fun delete (student: Student) // gör implementering
I den föregående koden lägger vi till en ny metod radera()
med en standardimplementering (även om jag inte lagt till den faktiska implementeringskoden för demonstration).
Vi har också friheten att åsidosätta standard implementeringen om vi vill.
klass StudentLocalDataSource: StudentRepository // ... åsidosätta roligt radera (student: Student) // do implementation
Som sagt kan ett Kotlin-gränssnitt ha egenskaper-men notera att det inte kan upprätthålla tillståndet. (Men kom ihåg abstrakta klasser kan behålla tillstånd.) Så följande gränssnittsdefinition med en fastighetsdeklaration kommer att fungera.
gränssnitt StudentRepository val propFoo: Boolean // kommer att fungera // ...
Men om vi försöker lägga till en del till gränssnittet genom att tilldela ett värde till fastigheten, fungerar det inte.
gränssnitt StudentRepository val propFoo: Boolean = true // Error: Egenskapsinitierare är inte tillåtna i gränssnitt // ...
En gränssnittsegenskap i Kotlin kan dock ha getter och setter metoder (men endast senare om egenskapen är mutable). Observera också att egendom i ett gränssnitt inte kan ha ett backfält.
gränssnitt StudentRepository var propFoo: Boolean get () = true set (value) om (värde) // gör något // ...
Vi kan också åsidosätta en gränssnittsegenskap om du vill, så att den omdefinieras.
klass StudentLocalDataSource: StudentRepository // ... åsidosätta var propFoo: Boolean get () = false set (värde) if (value)
Låt oss titta på ett fall där vi har en klass som implementerar flera gränssnitt med samma metodsignatur. Hur bestämmer klassen vilken gränssnittsmetod som ska ringas?
gränssnitt InterfaceA roligt funD () gränssnitt InterfaceB roligt funD ()
Här har vi två gränssnitt som har en metod med samma signatur fond()
. Låt oss skapa en klass som implementerar dessa två gränssnitt och åsidosätter fond()
metod.
klass klassA: InterfaceA, InterfaceB överride fun funD () super.funD () // Fel: Många supertyper tillgängliga, var god specificera den du menar i vinklar, t.ex. 'super'
Kompilatorn är förvirrad om att ringa super.funD ()
metod eftersom de två gränssnitt som klassen implementerar har samma metod signatur.
För att lösa detta problem sätter vi in gränssnittsnamnet för vilket vi vill ringa metoden i vinklar
. (IntelliJ IDEA eller Android Studio kommer att ge dig en ledtråd om hur du löser problemet när det går upp.)
klass klassA: InterfaceA, InterfaceB överrätta kul funD () super.funD ()
Här ska vi ringa fond()
metod av InterfaceA
. Problemet löst!
En ny klass (underklass) skapas genom att förvärva en befintlig klass (superklass) medlemmar och kanske omdefiniera sin standardimplementering. Denna mekanism är känd som arv i objektorienterad programmering (OOP). En av de saker som gör Kotlin så fantastisk är att den omfattar både OOP och funktionella programmeringsparadigmer - allt på ett språk.
Basklassen för alla klasser i Kotlin är Några
.
klass Person: Alla
De Några
typ motsvarar Objekt
typ vi har i Java.
public open class Any public open operatör rolig lika (andra: någon?): Boolean public open fun hashCode (): Int offentligt öppet roligt toString (): String
De Några
typ innehåller följande medlemmar: equals ()
, hash-kod()
, och även att stränga()
metoder (liknande Java).
Våra klasser behöver inte uttryckligen förlänga denna typ. Om du inte explicit anger vilken klass en ny klass sträcker sig, sträcker sig klassen Några
implicit. Av denna anledning behöver du vanligtvis inte inkludera : Någon
i din kod-vi gör det i koden ovan för demonstrationsändamål.
Låt oss nu titta på att skapa klasser i Kotlin med arv i åtanke.
klass Student klass GraduateStudent: Student ()
I koden ovan är Graduatestudent
klassen utökar superklassen Studerande
. Men den här koden kommer inte att kompileras. Varför? Eftersom klasser och metoder är slutlig
som standard i Kotlin. Med andra ord kan de inte utökas som standard - till skillnad från i Java där klasser och metoder är öppna som standard.
Programvaruteknik bästa praxis rekommenderar att du börjar börja göra dina klasser och metoder slutlig
som standard-dvs. om de inte specifikt är avsedda att omdefinieras eller överskridas i underklasser. Kotlin-teamet (JetBrains) tillämpade denna kodningsfilosofi och många fler bästa metoder för utveckling av detta moderna språk.
För att vi ska kunna skapa underklasser från en superklass måste vi uttryckligen markera superklassen med öppna
modifieringsmedel. Denna modifierare gäller även för alla typer av överklasser eller metoder som ska överdrivas av underklasser.
öppen klass Student
Vi lägger helt enkelt öppna
modifierare före klass
nyckelord. Vi har nu instruerat kompilatorn att tillåta vår Studerande
klass för att vara öppen för förlängning.
Som tidigare nämnts är medlemmar i en Kotlin-klass också slutliga som standard.
öppen klass Student öppen rolig skolfestival (): BigDecimal // gör implementering
I den föregående koden markerade vi skolavgifter
funktion som öppna
-så att underklasser kan åsidosätta det.
öppen klass GraduateStudent: Student () överträffa rolig schoolFees (): BigDecimal return super.schoolFees () + calculateSchoolFees () privata roliga beräknaSchoolFees (): BigDecimal // beräkna och returnera skolavgifter
Här öppet skolavgifter
funktion från superklassen Studerande
är överrullad av Graduatestudent
klass - genom att lägga till åsidosätta
modifierare före roligt
nyckelord. Observera att om du åsidosätter en medlem av en superklass eller ett gränssnitt, kommer det överordnade medlemmet också att vara öppna
som standard, som i exemplet nedan:
klass ComputerScienceStudent: GraduateStudent () överträffa rolig schoolFees (): BigDecimal return super.schoolFees () + calculateSchoolFess () privat kul calculateSchoolFess (): BigDecimal // beräkna och återvända skolavgifter
Även om vi inte markerade skolavgifter()
metod i Graduatestudent
klass med öppna
modifierar, kan vi fortfarande överstyra det - som vi gjorde i ComputerScienceStudent
klass. För oss för att förhindra detta måste vi markera den överordnade medlemmen som slutlig
.
Kom ihåg att vi kan lägga till ny funktionalitet till en klass - även om den är slutgiltig - med hjälp av anknytningsfunktioner i Kotlin. För en uppdatering av förlängningsfunktioner, kolla in mina avancerade funktioner i Kotlin-posten. Om du behöver en uppfriskning om hur du ger även en slutlig klass nya egenskaper utan att du ärva från det, läs avsnittet om förlängningsegenskaper i mina avancerade egenskaper och klasser efter.
Om vår superklass har en primärkonstruktor så här:
öppen klass Student (val firstName: String, val lastName: String) // ...
Då måste någon underklass ringa superklassens primära konstruktör.
öppen klass GraduateStudent (firstName: String, LastName: String): Student (firstName, LastName) // ...
Vi kan helt enkelt skapa ett objekt av Graduatestudent
klass som vanligt:
val graduateStudent = GraduateStudent ("Jon", "Snow") println (graduateStudent.firstName) // Jon
Om underklassen vill ringa superklasskonstruktören från sin sekundära konstruktör använder vi super
sökord (liknande hur superklasskonstruktörer åberopas i Java).
öppen klass GraduateStudent: Student // ... privat varavhandling: String = "" konstruktör (firstName: String, LastName: String, avhandling: String): super (firstName, lastName) this.thesis = thesis
Om du behöver en uppfriskning på klasskonstruktörer i Kotlin, vänligen besök mina klasser och objekt.
En annan fantastisk sak vi kan göra i Kotlin är att ge en typ ett alias.
Låt oss se ett exempel.
dataklass Person (val firstName: String, val lastName: String, val ålder: Int)
I klassen ovan kan vi tilldela Sträng
och int
typer för Person
egenskaper alias som använder typealias
modifierare i Kotlin. Den här modifieraren används för att skapa ett alias av någon typ i Kotlin-inklusive de du har skapat.
typalias Namn = String typalias Ålder = Int dataklass Person (val firstName: Namn, val sistnamn: Namn, valålder: Ålder)
Som du kan se har vi skapat ett alias namn
och Ålder
för båda Sträng
och int
typerna respektive. Vi har nu ersatt förnamn
och efternamn
egenskapstyp till vårt alias namn
-och även int
skriv till Ålder
alias. Observera att vi inte skapade några nya typer - vi skapade istället ett alias för typerna.
Dessa kan vara praktiska när du vill ge en bättre mening eller semantik till typer i din Kotlin-kodbas. Så använd dem klokt!
I denna handledning lärde du dig mer om objektorienterad programmering i Kotlin. Vi omfattade följande:
Om du har läst Kotlin genom vår Kotlin From Scratch-serie, se till att du har skrivit koden du ser och kör den på din IDE. Ett bra tips för att verkligen förstå ett nytt programmeringsspråk (eller något programmeringskoncept) du lär dig är att se till att du inte bara bara läser inlärningsresursen eller guiden utan också skriver in den faktiska koden och kör den!
I nästa handledning i Kotlin From Scratch-serien introduceras du för undantagshantering i Kotlin. Ses snart!
För att lära mig mer om Kotlins språket rekommenderar jag att du besöker Kotlins dokumentation. Eller kolla in några av våra andra Android App-utvecklingsposter här på Envato Tuts!