Kotlin nestede og indre klasser

1. Introduktion

I denne vejledning ser vi på fire måder at oprette indlejrede og indre klasser i Kotlin på.

2. Hurtig sammenligning med Java

For dem der tænker på Java indlejrede klasser, lad os lave en hurtig gennemgang af relaterede termer:

KotlinJava
Indre klasserIkke-statisk indlejrede klasser
Lokale klasserLokale klasser
Anonyme objekterAnonyme klasser
Indlejrede klasserStatisk indlejrede klasser

Selvom det bestemt ikke er identisk, kan vi bruge denne tabel som en vejledning, når vi tænker på mulighederne og brugssager for hver.

3. Indre klasser

For det første kan vi erklære en klasse i en anden klasse ved hjælp af nøgleordet indre.

Disse klasser har adgang til medlemmer af den lukkende klasse, endda private medlemmer.

For at bruge det skal vi først oprette en forekomst af den ydre klasse; vi kan ikke bruge indre klasser uden det.

Lad os oprette en Harddisk indre klasse inde i Computer klasse:

klasse Computer (val model: String) {indre klasse HardDisk (val sizeInGb: Int) {fun getInfo () = "Installeret på $ {[email protected]} med $ sizeInGb GB"}}

Bemærk, at vi bruger et kvalificeret udtryk for at få adgang til medlemmer af Computer klasse, som svarer til når vi gør det Computer. Dette i Java-ækvivalent med Harddisk.

Lad os nu se det i aktion:

@Test sjov givenHardDisk_whenGetInfo_thenGetComputerModelAndDiskSizeInGb () {val hardDisk = Computer ("Desktop"). HardDisk (1000) assertThat (hardDisk.getInfo ()) .isEqualTo ("Installeret på Computer (model = Desktop) med 1000 GB")}

4. Lokale indre klasser

Dernæst kan vi definere en klasse inde i en metodes krop eller i en scope-blok.

Lad os lave et hurtigt eksempel for at se, hvordan det fungerer.

Lad os først definere en tænd metode til vores Computer klasse:

sjov powerOn (): String {// ...}

Inde i tænd metode lad os erklære en Led klasse og få det til at blinke:

fun powerOn (): String {class Led (val color: String) {fun blink (): String {return "blinking $ color"}} val powerLed = Led ("Green") return powerLed.blink ()}

Bemærk, at omfanget af Led klasse er kun inde i metoden.

Med lokale indre klasser kan vi få adgang til og ændre variabler, der er erklæret i det ydre omfang. Lad os tilføje en defaultColor i tænd metode:

fun powerOn (): String {var defaultColor = "Blå" // ...} 

Lad os nu tilføje en changeDefaultPowerOnColor i vores Led klasse:

klasse Led (val farve: String) {// ... sjov changeDefaultPowerOnColor () {defaultColor = "Violet"}} val powerLed = Led ("Green") log.debug ("defaultColor is $ defaultColor") powerLed.changeDefaultPowerOnColor ( ) log.debug ("defaultColor ændret inden for Led" + "klasse til $ defaultColor")

Hvilke output:

[main] DEBUG c.b.n.Computer - standardColor er blå [main] DEBUG c.b.n.Computer - defaultColor ændret inden for LED-klasse til Violet

5. Anonyme objekter

Anonyme objekter kan bruges til at definere en implementering af en grænseflade eller en abstrakt klasse uden at skabe en genanvendelig implementering.

En stor forskel mellem anonyme objekter i Kotlin og anonyme indre klasser i Java er, at anonyme objekter kan implementere flere grænseflader og metoder.

Lad os først tilføje en Omskifter interface i vores Computer klasse:

interface Switcher {fun on (): String}

Lad os nu tilføje en implementering af denne grænseflade inde i tænd metode:

fun powerOn (): String {// ... val powerSwitch = object: Switcher {tilsidesættelse fun on (): String {return powerLed.blink ()}} return powerSwitch.on ()}

Som vi kan se, at definere vores anonyme afbryderen objekt bruger vi et objektudtryk. Vi er også nødt til at tage i betragtning, at hver gang objektudtrykket påberåbes, oprettes der en ny forekomst af objektet.

Med anonyme objekter som indre klasser kan vi ændre variabler, der tidligere er erklæret i omfanget. Dette skyldes, at Kotlin ikke har den effektive endelige begrænsning, vi har forventet i Java.

Lad os nu tilføje en changeDefaultPowerOnColor i vores Afbryderen modstand og kald det:

val powerSwitch = objekt: Switcher {// ... sjov changeDefaultPowerOnColor () {defaultColor = "Gul"}} powerSwitch.changeDefaultPowerOnColor () log.debug ("defaultColor ændret i powerSwitch" + "anonymt objekt til $ defaultColor")

Vi ser en output som denne:

... [main] DEBUG c.b.n.Computer - standardFarve ændret inden i powerSwitch anonymt objekt til Yellow

Bemærk også, at hvis vores objekt er en forekomst af en grænseflade eller en klasse med en enkelt abstrakt metode; vi kan oprette det ved hjælp af et lambda-udtryk.

6. Indlejrede klasser

Og sidst, vi kan definere en klasse i en anden klasse uden nøgleordet indre:

klasse Computer (val model: String) {klasse MotherBoard (val producent: String)}

I denne type klasse har vi ikke adgang til den ydre klasseinstans. Men vi kan få adgang ledsagerobjekt medlemmer af den indesluttende klasse.

Så lad os definere en ledsagerobjekt inde i vores Computer klasse for at se det:

ledsagende objekt {const val originCountry = "Kina" sjov getBuiltDate (): streng {return "2018-07-15T01: 44: 25.38Z"}}

Og så en metode indeni Moderkort for at få oplysninger om det og den ydre klasse:

sjov getInfo () = "Lavet af $ producent - $ originCountry - $ {getBuiltDate ()}"

Nu kan vi teste det for at se, hvordan det fungerer:

@Test fun givenMotherboard_whenGetInfo_thenGetInstalledAndBuiltDetails () {val motherBoard = Computer.MotherBoard ("MotherBoard Inc.") assertThat (motherBoard.getInfo ()) .isEqualTo ("Lavet af MotherBoard Inc. installeret i Kina - 2018-05-23")}

Som vi kan se, skaber vi moderkort uden en forekomst af Computer klasse.

7. Konklusion

I denne artikel har vi set, hvordan vi definerer og bruger indlejrede og indre klasser i Kotlin for at gøre vores kode mere kortfattet og indkapslet.

Vi har også set nogle ligheder med de tilsvarende Java-koncepter.

Et fuldt fungerende eksempel til denne vejledning kan findes på GitHub.


$config[zx-auto] not found$config[zx-overlay] not found