Kotlin From Scratch Abstrakte klasser, grensesnitt, arv og type alias

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. 

1. Abstrakte klasser

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

2. Grensesnitt

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:

  • En klasse kan implementere så mange grensesnitt som du vil, men det kan bare utvide en enkelt klasse (lik Java).
  • De overstyring Modifikator er obligatorisk i Kotlin-i motsetning til Java. 
  • Sammen med metoder kan vi også deklarere egenskaper i et Kotlin-grensesnitt. 
  • En Kotlin-grensesnittmetode kan ha en standardimplementering (lik Java 8). 

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! 

3. Arv

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. 

4. Bonus: Skriv alias

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! 

Konklusjon

I denne opplæringen lærte du mer om objektorientert programmering i Kotlin. Vi dekket følgende:

  • abstrakte klasser
  • grensesnitt 
  • arv
  • skriv alias

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!