Kotlin from Scratch Klassen en objecten

Kotlin is een moderne programmeertaal die compileert met Java bytecode. Het is gratis en open source en belooft om het coderen voor Android nog leuker te maken.  

In het vorige artikel leerde je geavanceerd gebruik van functies, zoals uitbreidingsfuncties, sluitingen, hogere orde functies en inline functies in Kotlin. 

In dit bericht krijg je een inleiding tot object-georiënteerd programmeren in Kotlin door te leren over klassen: constructors en eigenschappen, casting en meer geavanceerde klassefuncties die Kotlin gemakkelijk maakt. 

1. klassen

Een klasse is een programma-eenheid die functies en gegevens samenvoegt om een ​​aantal gerelateerde taken uit te voeren. We verklaren een klas in Kotlin met behulp van de klasse trefwoord - vergelijkbaar met Java. 

klasboek

De voorgaande code is de eenvoudigste klassenverklaring: we hebben zojuist een lege klasse gemaakt met de naam Boek.  We kunnen deze klasse nog steeds een instantie geven, zelfs als deze geen instantie bevat die de standaardconstructor gebruikt.

val boek = Boek ()

Zoals je kunt zien in de bovenstaande code, hebben we de nieuwe sleutelwoord om deze klasse te instantiëren, zoals gebruikelijk is in andere programmeertalen. nieuwe is geen trefwoord in Kotlin. Dit maakt onze broncode bondig bij het maken van een klasse-instantie. Maar houd er rekening mee dat voor het instantiëren van een Kotlin-klasse in Java de nieuwe trefwoord. 

// In een Java-bestand Boekboek = nieuw boek ()

Klasse-constructeurs en eigenschappen

Laten we eens kijken hoe we een constructor en eigenschappen aan onze klas kunnen toevoegen. Maar laten we eerst een typische klasse in Java bekijken:

/ * Java * / public class Book private String title; privé Long isbn; public Book (String title, Long isbn) this.title = title; this.isbn = isbn;  public String getTitle () return title;  public void setTitle (String title) this.title = title;  public Long getIsbn () return isbn;  public void setIsbn (Long isbn) this.isbn = isbn; 

Kijkend naar onze Boek modelklasse hierboven, we hebben het volgende:

  • twee velden: titel en isbn
  • een enkele constructor
  • getters en setters voor de twee velden (gelukkig kan IntelliJ IDEA ons helpen deze methoden te genereren)

Laten we nu kijken naar hoe we de vorige code in Kotlin kunnen schrijven in plaats van:

/ * Kotlin * / class Book var title: String var isbn: Long constructor (title: String, isbn: Long) this.title = title this.isbn = isbn

Een mooie nette klas! We hebben nu het aantal coderegels teruggebracht van 20 naar slechts 9. Het constructor () functie wordt a genoemd secundaire constructor in Kotlin. Deze constructor is equivalent aan de Java-constructor die we hebben gebruikt bij het instantiëren van een klasse. 

In Kotlin is er geen concept van een veld zoals je misschien kent; in plaats daarvan gebruikt het het concept van "eigenschappen". We hebben bijvoorbeeld twee veranderbare (lees-schrijf) eigenschappen die zijn gedeclareerd met de var trefwoord: titel en isbn in de Boek klasse. (Als je een opfriscursus over variabelen in Kotlin nodig hebt, bezoek dan het eerste bericht in deze reeks: Variabelen, Basistypen en Arrays). 

Het verbazingwekkende is dat de getters en setters voor deze eigenschappen automatisch door de Kotlin-compiler onder de motorkap worden gegenereerd. We hebben geen zichtbaarheidsmodifiers voor deze eigenschappen opgegeven, dus deze zijn standaard openbaar. Met andere woorden, ze zijn overal toegankelijk.

Laten we naar een andere versie van dezelfde klasse in Kotlin kijken:

klasse Book constructor (titel: String, isbn: Long) var title: String var isbn: Long init this.title = title this.isbn = isbn

In deze code hebben we de secundaire constructor verwijderd. In plaats daarvan hebben we een constructor in de klassenheader a genoemd primaire constructor. Een primaire constructor heeft geen plaats om een ​​codeblok te plaatsen, dus gebruiken we de in het modifier om inkomende parameters van de primaire constructor te initialiseren. Merk op dat de in het codeblok wordt onmiddellijk uitgevoerd wanneer de klasse-instantie is gemaakt.

Zoals u kunt zien, heeft onze code nog steeds veel overzicht. Laten we het verder verkleinen:

class Book constructor (var title: String, var isbn: Long)

Onze Boek klasse is nu slechts één regel code. Dat is echt cool! Merk op dat we in de parameterlijst van de primaire constructor onze veranderbare eigenschappen hebben gedefinieerd: titel en isbn rechtstreeks in de primaire constructor met de var trefwoord. 

We kunnen ook standaardwaarden toevoegen aan elk van de klasse-eigenschappen in de constructor.

class Book constructor (var title: String = "default value", var isbn: Long)

In feite kunnen we ook het bouwer zoekwoord, maar alleen als er geen zichtbaarheidsmodifier is (openbaar, privaat, of beschermde) of eventuele annotaties. 

class Book (var title: String = "default value", var isbn: Long)

Een heel nette klas, moet ik zeggen!

We kunnen nu een klasse-instantie zoals deze maken:

val book = Book ("Een lied van ijs en vuur", 9780007477159) val book2 = Book (1234) // gebruikt de standaardwaarde van het titelobject

Eigenschappen openen en instellen 

In Kotlin kunnen we een eigenschap krijgen door het object van de klas boek, gevolgd door een puntscheidingsteken ., dan de eigenschapnaam titel. Deze beknopte stijl van toegang tot eigenschappen wordt genoemd syntaxis voor eigendomsrechten. Met andere woorden, we hoeven niet de eigenschap getter-methode te bellen om de setter te openen of de setter te bellen om een ​​eigenschap in Kotlin in te stellen - zoals we doen in Java. 

println (book.title) // "A Song of Ice and Fire"

omdat de isbn eigendom wordt aangegeven met de var sleutelwoord (lezen-schrijven), we kunnen ook de eigenschapswaarde wijzigen met behulp van de toewijzingsoperator =.

book.isbn = 1234 println (book.isbn) // 1234

Laten we nog een voorbeeld bekijken:

class Book (var title: String, val isbn: Long) val book = Book ("A Song of Ice and Fire", 9780007477159) book.isbn = 1234 // fout: alleen-lezen eigenschap book.title = "Dingen vallen uiteen "// opnieuw toegewezen titel met waarde

Hier hebben we het isbn parameter in plaats daarvan onveranderlijk (alleen-lezen) door de. te gebruiken val trefwoord. We hebben een klasse-instance geconcretiseerd boek en heeft de. opnieuw toegewezen titel bezit de waarde "Things Fall Apart". Merk op dat toen we probeerden om de isbn eigenschapswaarde voor 1234, de compiler klaagde. Dit komt omdat de eigenschap onveranderlijk is, te zijn gedefinieerd met de val trefwoord. 

Java-interoperabiliteit

Houd er rekening mee dat door een parameter te declareren met de var modifier in de primaire constructor, heeft de Kotlin-compiler (achter de schermen) ons geholpen om zowel de eigenschap accessors: getter en setter te genereren. Als je gebruikt val, het genereert alleen de vangstof. 

/ * Kotlin * / class Book (var title: String, val isbn: Long)

Dit betekent dat Java-bellers het eigenschapsveld eenvoudig kunnen ophalen of instellen door respectievelijk de methode setter of getter van de eigenschap aan te roepen. Let op: dit is afhankelijk van de modifier die wordt gebruikt om de Kotlin-eigenschap te definiëren: var of val

/ * Java * / Boekboek = nieuw boek ("A Song of Ice and Fire", 9780385474542) println (book.getTitle ()) // "A Song of Ice and Fire" book.setTitle ("Things Fall Apart") // stelt nieuwe waarde in println (book.getTitle ()) // "Things Fall Apart" book.getIsbn () // 9780385474542 book.setIsbn (4545454) // zal niet compileren

Aangepaste Getters en Setters

In deze sectie laat ik je zien hoe je aangepaste toegangen (getters en setters) voor een woning in Kotlin kunt maken als je dat wilt. Het maken van een aangepaste setter kan handig zijn als u een waarde wilt valideren of verifiëren voordat deze is ingesteld als een klasseneigenschap. En een aangepaste eigenschap-getter kan handig zijn wanneer u de waarde die moet worden geretourneerd wilt wijzigen of wijzigen.  

Een Custom Setter maken

Omdat we onze eigen aangepaste getter of setter voor een eigenschap willen maken, moeten we die eigenschap in de hoofdtekst van de klasse definiëren in plaats van de kop van de constructor. 

class Book (val isbn: Long) var title = "default value"

Dit is de reden waarom we het veranderbare (lees-schrijf) hebben verplaatst titel eigenschap in de klasse body en gaf het een standaardwaarde (anders zou het niet compileren).  

class Book (val isbn: Long) var title = "default value" set (value) if (! value.isNotEmpty ()) throw IllegalArgumentException ("Titel mag niet leeg zijn") field = value

Je kunt zien dat we onze eigen settermethode hebben gedefinieerd set (waarde) voor de titel direct onder de eigenschapsdefinitie - merk op dat je dit niet kunt wijzigen set () methode handtekening, omdat dit is wat de compiler verwacht als aangepaste eigenschap setter functie.

De parameter waarde doorgegeven aan de reeks methode vertegenwoordigt de werkelijke waarde die door gebruikers aan de eigenschap is toegewezen - u kunt de parameternaam desgewenst wijzigen, maar waarde heeft veel de voorkeur. We hebben het waarde door te controleren of de waarde leeg is. Indien leeg, stop de uitvoering en gooi een uitzondering; anders de waarde opnieuw toewijzen aan een special veld- veranderlijk.

Deze special veld- variabel veld in de reeks methode is een alias voor het achtergrondveld van de eigenschap: een achtergrondveld is slechts een veld dat wordt gebruikt door eigenschappen wanneer u die veldgegevens wilt wijzigen of gebruiken. anders waarde, je kunt deze special niet hernoemen veld- veranderlijk.

Een aangepaste getter maken

Het is heel gemakkelijk om een ​​aangepaste getter voor een woning in Kotlin te maken. 

class Book (val isbn: Long) var title = "default value" // ... set method get () return field.toUpperCase ()

Binnen in de krijgen methode, we geven eenvoudigweg een aangepast terug veld--in ons geval hebben we de titel van het boek in hoofdletters teruggestuurd. 

val book = Book (9780007477159) book.title = "A Song of Ice and Fire" println (book.title) // "A SONG OF ICE AND FIRE" println (book.isbn) // 9780007477159

Merk op dat elke keer dat we een waarde instellen op de titel eigendom, zijn reeks methode blok wordt uitgevoerd-hetzelfde geldt voor de krijgen methode elke keer dat we het terughalen. 

Als u meer wilt weten over lidfuncties voor een Kotlin-klasse (het soort functie dat is gedefinieerd in een klasse, object of interface), gaat u naar de functie Meer plezier met functies in deze serie. 

Meer over Constructors

Zoals ik eerder heb besproken, hebben we twee soorten constructeurs in Kotlin: primair en secundair. We hebben de vrijheid om beide in één klas te combineren, zoals u in het onderstaande voorbeeld kunt zien:

class Car (valnaam: String, val plateNo: String) var new: Boolean = true constructor (naam: String, plateNo: String, new: Boolean): this (name, plateNo) this.new = new

Merk op dat we eigenschappen niet binnen een secundaire constructor kunnen declareren, zoals we deden voor de primaire constructor. Als we dit willen doen, moeten we dit binnen het klasselichaam declareren en het dan initialiseren in de secundaire constructor.  

In de bovenstaande code stellen we de standaardwaarde van de nieuwe eigendom voor de klas Auto (onthouden, nieuwe is geen trefwoord in Kotlin) - we kunnen dan de secundaire constructor gebruiken om het te veranderen als we dat willen. In Kotlin moet elke secundaire constructor de primaire constructor aanroepen, of een andere secundaire constructor bellen die de primaire constructor oproept - we gebruiken de deze sleutelwoord om dat te bereiken. 

Merk ook op dat we meerdere secundaire constructors in een klasse kunnen hebben. 

class Car (val name: String, val plateNo: String) var new: Boolean? = null var color: String = "" constructor (naam: String, plateNo: String, new: Boolean): this (name, plateNo) this.new = new constructor (naam: String, plateNo: String, new: Boolean , color: String): this (name, plateNo, new) this.colour = color

Als een klasse een superklasse uitbreidt, kunnen we de superklasse gebruiken super keyword (vergelijkbaar met Java) om de constructor van de superklasse aan te roepen (we zullen overerving in Kotlin in een toekomstige post bespreken). 

// roept direct de primaire constructor val car1 = Auto aan ("Peugeot 504", "XYZ234") // roept direct de 1e sec. constructor val car2 = Auto ("Peugeot 504", "XYZ234", false) // roept de laatste seconde rechtstreeks op constructor val car3 = Auto ("Peugeot 504", "XYZ234", false, "gray") 

Zoals ik eerder al zei, moeten we expliciet een zichtbaarheidsmodifier toevoegen aan een constructeur in een klas bouwer zoekwoord: constructors zijn standaard openbaar. 

class Car private constructor (valnaam: String, val plateNo: String) // ... 

Hier hebben we de constructor privé gemaakt. Dit betekent dat gebruikers een object niet rechtstreeks met behulp van de constructor kunnen instantiëren. Dit kan handig zijn als u wilt dat gebruikers in plaats daarvan een andere methode (een fabrieksmethode) aanroepen om onrechtstreeks objecten te maken. 

2. Alle soorten en soorten

In Kotlin wordt het bovenste type in de typehiërarchie aangeroepen Ieder. Dit komt overeen met Java Voorwerp type. Dit betekent dat alle klassen in Kotlin expliciet erven van de Ieder type, inclusief DraadInt, Dubbele, enzovoorts. De Ieder type bevat drie methoden: is gelijk aantoString, en hashcode

We kunnen ook de Niets class in Kotlin in functies die altijd een uitzondering retourneren - met andere woorden, voor functies die niet normaal eindigen. Wanneer een functie terugkeert Niets, dan weten we dat het een uitzondering zal werpen. Geen equivalent type van deze soort bestaat op Java. 

fun throwException (): Nothing throw Exception ("Uitzonderingsbericht)

Dit kan van pas komen bij het testen van foutafhandelingsgedrag in uw unit tests.   

3. Zichtbaarheidsverbeteraars

Zichtbaarheidsmodifiers helpen ons om de toegankelijkheid van onze API voor het publiek te beperken. We kunnen verschillende zichtbaarheidmodifiers leveren voor onze klassen, interfaces, objecten, methoden of eigenschappen. Kotlin biedt ons vier zichtbaarheidsmodifiers:

Openbaar

Dit is de standaardinstelling en elke klasse, functie, eigenschap, interface of object met deze modifier is overal toegankelijk.

Privaat 

Een functie, interface of klasse op het hoogste niveau die is gedeclareerd als privaat is alleen toegankelijk binnen hetzelfde bestand. 

Elke functie of eigenschap die is gedeclareerd privaat in een klasse, object of interface kan alleen zichtbaar zijn voor andere leden van dezelfde klasse, object of interface. 

class Account private val amount: Double = 0.0

beschermde

De beschermde modifier kan alleen worden toegepast op eigenschappen of functies in een klasse, object of interface. Het kan niet worden toegepast op hoofdfuncties, klassen of interfaces. Eigenschappen of functies met deze modifier zijn alleen toegankelijk binnen de klasse die deze definieert en elke subklasse. 

intern 

In een project met een module (Gradle- of Maven-module), een klasse, object, interface of functie gespecificeerd met de intern modifier gedeclareerd binnen die module is alleen toegankelijk vanuit die module. 

interneklas Account val amount: Double = 0.0

4. Smart Casting

Gieten betekent een object van een ander type nemen en het in een ander objecttype converteren. In Java gebruiken we bijvoorbeeld de instanceof operator om te bepalen of een bepaald objecttype van een ander type is voordat we het vervolgens casten.

/ * Java * / if (shape instanceof Circle) Cirkelcirkel = (Cirkel) vorm; circle.calCircumference (3.5); 

Zoals je kunt zien, hebben we gecontroleerd of vorm instantie is Cirkel, en dan moeten we expliciet de vorm verwijzing naar a Cirkel type zodat we methoden van de cirkel type. 

Een ander geweldig ding over Kotlin is de intelligentie van de compiler als het gaat om gieten. Laten we nu een versie in Kotlin bekijken.

/ * Kotlin * / if (vorm is Circle) shape.calCircumference (3.5)

Best netjes! De compiler is slim om te weten dat de als blok wordt alleen uitgevoerd als de vorm object is een instantie van Cirkel-dus het gietmechanisme wordt voor ons onder de motorkap gedaan. We kunnen nu gemakkelijk eigenschappen of functies van de Cirkel typ in de als blok. 

if (shape is Circle && shape.hasRadius ()) println ("Cirkelradius is shape.radius")

Hier, de laatste toestand na de && in de als header wordt alleen aangeroepen als de eerste voorwaarde is waar. Als het vorm is geen Cirkel, dan zal de laatste voorwaarde niet worden geëvalueerd. 

5. Expliciete casting

We kunnen de gebruiken zoals operator (of onveilige cast operator) om expliciet een referentie van een type naar een ander type in Kotlin te casten. 

valcirkel = vorm als cirkelcirkel. calCircumference (4)

Als de expliciete castingbewerking illegaal is, houd er dan rekening mee dat a ClassCastException zal worden gegooid. Om te voorkomen dat een uitzondering wordt gegooid tijdens het casten, kunnen we de veilige cast operator (of operator met nullable cast) zoals?

val cirkel: Cirkel? = vorm als? Cirkel

De zoals? operator probeert naar het bedoelde type te casten en keert terug nul als de waarde niet kan worden gegoten in plaats van een uitzondering te genereren. Houd er rekening mee dat een soortgelijk mechanisme is besproken in de sectie Nullability in Nullability, Loops en Voorwaarden in deze reeks. Lees daar voor een opfriscursus.

6. Objects

Objecten in Kotlin lijken meer op JavaScript-objecten dan Java-objecten. Merk op dat een object in Kotlin geen instantie van een specifieke klasse is!

Objecten lijken erg op klassen. Hier zijn enkele kenmerken van objecten in Kotlin:

  • Ze kunnen eigenschappen, methoden en een hebben in het blok.
  • Deze eigenschappen of methoden kunnen zichtbaarheidsmodifiers hebben.
  • Ze kunnen geen constructeurs hebben (primair of secundair).
  • Ze kunnen andere klassen uitbreiden of een interface implementeren.

Laten we nu ingaan op het maken van een object.  

object Singleton fun myFunc (): Unit // do something

We plaatsen de voorwerp sleutelwoord vóór de naam van het object dat we willen maken. In feite creëren we singletons wanneer we objecten maken in Kotlin met behulp van de voorwerp construct, omdat er maar één exemplaar van een object bestaat. U leert hier meer over als we de objectinteroperabiliteit met Java bespreken. 

Een singleton is een softwareontwerppatroon dat garandeert dat een klasse slechts één exemplaar heeft en dat die klasse een globaal toegangspunt biedt. Telkens wanneer meerdere klassen of clients de klas vragen, krijgen ze dezelfde instantie van de klas. Je kunt mijn bericht over het singleton-patroon in Java bekijken voor meer informatie.

U kunt overal in uw project toegang krijgen tot het object of singleton, zolang u het pakket importeert. 

Singleton.myFunc ()

Als u een Java-coder bent, maken we meestal singletons:

openbare klasse Singleton private static Singleton INSTANCE = null; // andere instantievariabelen kunnen hier privé zijn Singleton () ; public statisch gesynchroniseerd Singleton getInstance () if (INSTANCE == null) INSTANCE = nieuwe Singleton ();  return (INSTANCE);  // andere instantie-methoden kunnen volgen

Zoals je kunt zien, met behulp van de Kotlin voorwerp constructie maakt het beknopt en eenvoudiger om singletons te maken. 

Objecten in Kotlin kunnen ook worden gebruikt om constanten te maken. Gewoonlijk maken we in Java constanten in een klasse door deze als een openbaar statisch laatste veld als volgt te maken:

publieke slotklasse APIConstants public static final String baseUrl = "http://www.myapi.com/"; private APIConstants () 

Deze code in Java kan op deze manier bondiger in Kotlin worden omgezet:

package com.chike.kotlin.constants object APIConstants val baseUrl: String = "http://www.myapi.com/"

Hier hebben we de constante verklaard APIConstants met een eigendom baseurl in een pakket com.chike.kotlin.constants. Onder de motorkap een Java-statisch privélid baseurl is voor ons gemaakt en geïnitialiseerd met de tekenreeks-URL. 

Als u deze constante in een ander pakket in Kotlin wilt gebruiken, importeert u eenvoudigweg het pakket.

import com.chike.kotlin.constants.APIConstants APIConstants.baseUrl

Java-interoperabiliteit

Kotlin converteert een object naar een definitieve Java-klasse onder de motorkap. Deze klasse heeft een eigen statisch veld AANLEG die een enkele instantie (een singleton) van de klas bevat. De volgende code laat zien hoe eenvoudig gebruikers een Kotlin-object vanuit Java kunnen bellen. 

/ * Java * / Singleton.INSTANCE.myFunc ()

Hier, een Java-klasse genoemd eenling werd gegenereerd met een openbaar statisch definitief lid AANLEG, inclusief een publieke eindfunctie myFunc ().

Om de objectfunctie of -eigenschap in Kotlin een statisch lid van de gegenereerde Java-klasse te maken, gebruiken we de @JvmStatic annotatie. Hier is hoe het te gebruiken:

object Singleton @JvmStatic fun myFunc (): Unit // do something

Door de @JvmStatic annotatie aan myFunc (), de compiler heeft het omgezet in een statische functie. 

Nu kunnen Java-bellers het noemen als een normale statische lid-oproep. Merk op dat het gebruik van de AANLEG statische velden om leden te bellen, werken nog steeds.

/ * Java * / Singleton.myFunc ()

7. Companion-objecten

Nu hebben we begrepen welke objecten in Kotlin zijn, laten we duiken in een ander soort objecten die metgezelobjecten worden genoemd. 

Omdat Kotlin geen statische klassen, methoden of eigenschappen ondersteunt zoals die we op Java hebben, heeft het Kotlin-team ons een krachtiger alternatief geboden, genaamd metgezel objecten. Een begeleidend object is in feite een object dat tot een klasse behoort - deze klasse staat bekend als de begeleidende klasse van het object. Dit betekent ook dat de kenmerken die ik heb genoemd voor objecten ook van toepassing zijn op begeleidende objecten. 

Een begeleidend object maken

Net als bij statische methoden in Java, is een begeleidend object niet gekoppeld aan een klasse-instantie maar eerder aan de klasse zelf, bijvoorbeeld een statische methode in de fabriek, die de taak heeft om een ​​klasse-instantie te maken. 

class Persoon private constructor (var firstName: String, var lastName: String) companion-object fun create (firstName: String, lastName: String): Person = Person (firstName, lastName)

Hier hebben we de constructeur gemaakt privaat-dit betekent dat gebruikers buiten de klasse geen instantie rechtstreeks kunnen maken. In ons bijbehorende objectblok hebben we een functie create (), welke een creëert Persoon object en retourneert het. 

Een begeleidende objectfunctie aanroepen

metgezel object-instantiatie is lui. Met andere woorden, het zal de eerste keer alleen worden geïnstantieerd wanneer dit nodig is. De instantiatie van een metgezel object gebeurt wanneer een instantie van de metgezel klasse is gemaakt of de metgezel objectleden worden benaderd. 

Laten we eens kijken hoe een metgezel-objectfunctie in Kotlin op te roepen.

val person = Person.create ("Cersei", "Lannister") println (person.firstName) // print "Cersei"

Zoals u kunt zien, is dit hetzelfde als een normale statische methode in Java aanroepen. Met andere woorden, we bellen gewoon de klas en bellen dan het lid. Merk op dat we naast functies ook eigenschappen kunnen hebben in ons begeleidende object. 

class Persoon private constructor (var firstName: String, var lastName: String) init count ++ begeleidende object var count: Int = 0 fun create (firstName: String, lastName: String): Person = Person (firstName, lastName) init println ("Persoonsobject gemaakt")

Merk ook op dat de metgezel klasse heeft onbeperkte toegang tot alle eigenschappen en functies die zijn gedeclareerd in het bijbehorende object, terwijl een bijbehorend object geen toegang heeft tot de klasleden. We kunnen een hebben in het codeblok binnen een metgezel object - dit wordt onmiddellijk aangeroepen wanneer het begeleidende object wordt gemaakt. 

Person.create ("Arya", "Stark") Person.create ("Daenerys", "Targaryen") println (Person.count)

Het resultaat van het uitvoeren van de bovenstaande code is: 

Persoon begeleidend object gemaakt 2

Onthoud, slechts één instantie van een klasse metgezel object kan ooit bestaan. 

We zijn ook vrij om ons begeleidende object een naam te geven. 

// ... begeleidende object Factory var count: Int = 0 fun create (firstName: String, lastName: String): Person = Person (firstName, lastName) // ... 

Hier hebben we het een naam gegeven Fabriek. We kunnen het zo in Kotlin noemen:

Person.Factory.create ("Petyr", "Baelish")

Deze stijl is breedsprakig, dus het houden van de vorige manier heeft veel de voorkeur. Maar dit kan van pas komen als u een bijbehorende objectfunctie of eigenschap vanuit Java aanroept.

Zoals eerder gezegd, zoals objecten, kunnen begeleidende objecten ook eigenschappen of functies bevatten, interfaces implementeren en zelfs een klasse uitbreiden. 

interface PersonFactory fun create (firstName: String, lastName: String): Person class Person private constructor (var firstName: String, var lastName: String) companion object: PersonFactory overschrijven leuk maken (firstName: String, lastName: String) : Persoon retourpersoon (firstName, lastName)

Hier hebben we een interface PersonFactory met slechts een single create () functie. Kijkend naar onze nieuwe gewijzigd metgezel object, implementeert het nu deze interface (je leert in een later bericht over interfaces en overerving in Kotlin). 

Java-interoperabiliteit

Onder de motorkap worden vergelijkbare objecten gecompileerd op dezelfde manier als waarop een Kotlin-object is gecompileerd. In ons eigen geval worden er twee klassen voor ons gegenereerd: een finale Persoon klasse en een innerlijke statische eindklasse Persoon $ Companion

De Persoon klasse bevat een laatste statisch lid genaamd Metgezel-dit statische veld is een object van de Persoon $ Companion innerlijke klasse. De Persoon $ Companion innerlijke klasse heeft ook zijn eigen leden, en een van hen is een publieke finale functie genaamd create ()

Merk op dat we ons begeleidende object geen naam hebben gegeven, dus de gegenereerde statische innerlijke klasse was Metgezel. Als we het een naam hadden gegeven, dan zou de gegenereerde naam de naam zijn die we hem in Kotlin hebben gegeven. 

/ * Java * / Person persoon = Person.Companion.create ("Jon", "Snow"); 

Hier heeft het metgezelobject in Kotlin geen naam, dus gebruiken we de naam Metgezel geleverd door de compiler voor Java-bellers om het te bellen.

De @JvmStatic annotatie toegepast op een begeleidend objectlid werkt op dezelfde manier als hoe het werkt voor een gewoon object. 

Companion-objectextensies

Op dezelfde manier als uitbreidingsfuncties de functionaliteit van een klasse kunnen uitbreiden, kunnen we ook de functionaliteit van een begeleidend object uitbreiden. (Als je een opfriscursus op uitbreidingsfuncties in Kotlin wilt, bezoek dan de tutorial Advanced Functions in deze reeks). 

class ClassA companion object  fun ClassA.Companion.extFunc () // ... do implementation ClassA.extFunc ()

Hier hebben we een uitbreidingsfunctie gedefinieerd extFunc () op het bijbehorende object ClassA.Companion. Met andere woorden, extfunc () is een extensie van het bijbehorende object. Dan kunnen we de extensie bellen alsof het een ledenfunctie is (het is niet!) Van het bijbehorende object. 

Achter de schermen zal de compiler een statische utiliteitsfunctie creëren extFunc (). Het receiver-object als argument voor deze utiliteitsfunctie is ClassA $ Companion

Conclusie

In deze tutorial leer je over basislessen en objecten in Kotlin. We hebben het volgende behandeld over klassen:

  • klasse creatie
  • constructeurs
  • eigenschappen
  • zichtbaarheidsmodifiers
  • slimme casting
  • expliciete casting 

Ook heb je geleerd hoe objecten en bijbehorende objecten in Kotlin je statische methoden, constanten en singletons die je in Java codeert, gemakkelijk kunnen vervangen. Maar dat is niet alles! Er is nog meer te leren over lessen in Kotlin. In het volgende bericht laat ik je nog meer coole functies zien die Kotlin heeft voor objectgeoriënteerd programmeren. Tot ziens!

Voor meer informatie over de Kotlin-taal, raad ik aan de Kotlin-documentatie te bezoeken. Of bekijk enkele van onze andere Android-apps voor app-ontwikkeling hier op Envato Tuts+!