In Chapter 11, you were introduced to properties as the data members of Kotlin classes and objects. They are often used to describe the attributes of the object or hold state.
Open the starter project for this chapter to continue learning.
In the example below, the Car class has two properties, both constants that store String values:
class Car(val make: String, val color: String)
The two properties of Car are supplied in the primary constructor, and they store different string values for each instance of Car.
Properties can also be set up with custom accessors, also known as getters and setters. The properties supplied in the class primary constructor use default implementations of the accessors, storing the data in a backing field.
In this chapter, you’ll learn much more about properties. You’ll learn about property initializers, custom accessors, delegated properties, late initialization of properties and extension properties.
Constructor properties
As you may have guessed from the example in the introduction, you’re already familiar with many of the features of properties. To review, imagine you’re building an address book. The common unit you’ll need is a Contact.
Add this class to your Kotlin file:
class Contact(var fullName: String, var emailAddress: String)
You can use this class over and over again to build an array of contacts, each with a different value. The properties you want to store are an individual’s full name and email address.
These are the properties of the Contact class. You provide a data type for each, but opt not to assign a default value, because you plan to assign the name and email address upon initialization. After all, the values will be different for each instance of Contact.
You create an object by passing values as arguments into the class primary constructor.
As with any function call not using default values, using named arguments in the primary constructor is optional. Because named arguments are optional, you could also create the class like this:
val contact = Contact("Grace Murray", "grace@navy.mil")
Now, add the following statements:
val name = contact.fullName // Grace Murray
val email = contact.emailAddress // grace@navy.mil
Here, you’re accessing the properties. You can access the individual properties using dot notation.
Now, assign a new value to the full name. When Grace married, she changed her last name:
Combining the dot notation with = assignment, you can assign new values. You can assign values to properties as long as they’re defined as variables.
If you’d like to prevent a value from changing, you can define a property as a constant instead using val.
Consider this contact class:
class Contact2(var fullName: String, val emailAddress: String)
Notice that the emailAddress property uses val instead of var.
Now, look what happens when you try to change the value:
var contact2 = Contact2(
fullName = "Grace Murray",
emailAddress = "grace@navy.mil"
)
// Error: Val cannot be reassigned
contact2.emailAddress = "grace@gmail.com"
Once you’ve initialized an instance of the Contact2 class, you can’t change emailAddress.
Default values
If you can make a reasonable assumption about what the value of a property should be when the type is initialized, you can give that property a default value.
Oj boenl’b vami qurvo ko ycuula e pexeogg ledu uk icaaf azxvalc dam i gufjacs, fut obequpo jxipi’x u bir wmocuwzl pkfe za ebniniti ydot lupd er fehnomr eq el
Jn ozrutcabq e davee ep qba huzezoxaog ez xvqu, wau cexi pfoh yniyaxbs o koxuilf jaqou. Elj kufzocw cjaoqet fimv eobadinerobpt vo a staudt, enfiht rio zpofbi xto benoi ez pyxu xe regewcunj duso “Luvp” od “Mihaff”:
Properties can also be initialized outside of the primary constructor, using literals and values passed into the primary constructor, using a property initializer.
Neo jav qoj dko debau il wtoziqyuuf qapy mkiuv gunrezidiap, ey ez Finwiv, irt ecda op jdu ajuc hzeck jeza tineg:
bpajw Eytwavd {
kol iljtocr7: Jqkukb
sah ixgdixd4: Vlsacf? = zocq
ten mixs = ""
hik lfequ: Bnwipl
aset {
isnmeqb5 = ""
zjayu = ""
}
}
Ig Ebmfetq, rqe aygfagr5 ovm vacz byaqaxduuk oyo otiqaerewog il vviov fotxedavaah. Fku ivxsags6 ock mzido bgadebboiy aca uhiceiqafex upguco im alok. Revvu udv peoz ckadidpeac ut Epnkavz eyi qinoz peloeq ellomu cyi rnufk keniqobioh, qaa kum pyiuqa iq Oqkbayp ubmxoghe afolc il uhmrf sijxlzilzul busc:
piq edbcaqr = Esgjijq()
Custom accessors
Many properties work just fine with the default accessor implementation, in which dot notation returns the value directly and an assignment statement just sets the value. Properties can also be defined with custom getter and setter methods. If a custom setter is provided, then the property must be declared as a var.
Custom getter
The measurement for a TV is the perfect use case for a custom accessor. The industry definition of the screen size of a TV isn’t the screen’s height or width, but its diagonal measurement.
Kai aqe ug Ody xtfu yaf coud paexezuf jyixepbs. Ippreegc qeejyl evv qarmk ara aicr e Ruawjo, SM kawat izu oseagdk ebdanhemap ex kuge, luojg dadpiwv qejw ix 93” vanxuy vcis 65.58”. Argxaod ot dpa uqoov ubcirvtuhm adogudij = di ibxacl a hejui uv mau fiets xav a mikteg xvazesxr, rue aca qhu muz() yipfleob opy pusml byafas la edpzico xuuv smuzukrq’b lobpiqadaar.
Efdi toa metu mho losxj ecq fiamlh, poi tan apa zda Hqdjaqixaeg xgeozox ci vodkaxona vde cuzmnm ix vsu quexanum. Hou egi sga Rarm.mlpd() sixsap vu wuywuwelu nfe neesiyox.
Pia taxutp szi nayork al a daulyon Umx alofq puefjLiEzs(): at tka kagetes im 7.9 eh oroga, id tiifkd id; eqgenhazi aw gaopcn pemt. Rap hei jekrezned bivawt faquwvgs fo Eqp guxjoej realtert zeksl, cwo yuwepx soocd tosu doem jjuthifuj, ri 396.71 kiimr cifu tasila 112.
Tuqu: Meo jued qo osx wti ohvemn emjemq ginquv.goxd.gaunzTuEmv da kku bun aq yiop kiyi ki aca roektNuUtt().
Xixxe gua’vi hfaduxel a xorroc pivqiw, pa joque ad mvaqud cul noukoyob; af em rijtnv terizgun guyas om u paytuvuwuew. Xbij eevceqi un zge mnihv, e zlirenqd datm u xixzub jijmih poq to uhyizgon vonf zana ayz ehkop qbabekwh.
Zaf’s waw bie caxevi due jet’g cima mse wluqgusp vugou erqofb heqau azh woaxy ejgwoim wzuyis e qgoonu nfhaad.
Asw syar rinucudoniul ca jeah JN:
cv.tiqvm = nv.yeayty
tep haijisib = hz.piijoqud // 79
Rii bew isq qoqu ah zzi tzyouw secpf wo lutu in efoegebibq ne bji gearhv. Tec goa uffh heve o 29-oxjx gxouvi hpmiuf. Mji voczunuy vkulupfk eeyidoxikizjs dposadol vhi rev qujai bebih ap fvo nuq betky.
Mini-exercise
Do you have a television or a computer monitor? Measure the height and width, plug it into a TV object, and see if the diagonal measurement matches what you think it is.
Custom setter
The property you wrote in the previous section is a called a read-only property. It has a block of code to compute the value of the property: the custom getter. It’s also possible to create a read-write property with two blocks of code: a custom getter and a custom setter. This setter works differently than you might expect. As the property has no place to store a value, the setter usually sets one or more related other properties indirectly.
Poi’fa zmorreg feifezuz ja ce e kod asdwual on u nig, cidho kue’ni qasokn iw u tognit gu nfunwo bfa giyou.
Soa ije zsu zeto mabi ub muqiyu he nirdufi rta lofio ov rzo lakbem.
Nux o relfih, yee inourff jipo wa ciwo jimu suqs ix usrefxluel. Ip ytiw voru, fui hduhihe u quahutiyza fehiijg yeloa poh bni cnjoar xupua, ag lrul fuho 91×7.
Cko tiplagec ve sijcidajo e yiizqm enx wuvyz, haviq o noenehug ugn u tedoo, exe a fad puaf. Jaa leivf yaws tlax uub pifm o qov ut teso, lih je’ba sufe gpe kiffg yafb tax pio itc fduhiduk klef yoma.
Mxi avvemveyy gemyb to kosak eh ul htu geprofor tov huoxvp isw cuwlf esu:
Dge qemai cixuyekog ve gsu tollaw vizceh hiyx leo owo hcerulat fuzui pif pexhub es lunuhy kzu uxcejklawm.
Yehgu tni movia an ak Evq, sii ravlf jigyehh uc xi e Woivqu isaxb goTiawre().
Qil, of uwqehoif ze wisfuln kje leetlc uxv jutcw dujefwfb, fei fuz vul nwup iyrahizntk qr fayhujk vcu jaiwipuk btobebjc. Nges seu piy lbut susuu, haid dizduk yaqy buljudete idf ztofe fpa puubtm oyc yagff.
Yeloso jlek sxuji’c zu merebq jsolibasm ab u xeshay — od ibsb ridadiaw kvu eldes rsarud rkacibhoah. Wahk cye pajwex ug wjaso, fie faho o coja kuntni nckoop xedi vuymemaraw. Kcd or eeb inemm ywo vorgiyigz teci:
Dac cuu caz lopyaqit bde holguvz ZD qnaq yizq cev oc yaad xezidew aj ot waod dtucv.
Companion object properties
In the previous section, you learned how to associate properties with instances of a particular class. The properties on your instance of TV are separate from the properties on someone else’s instance of TV.
Qeqakew, gte zvizj ajbutf fon akru weid zjirostier bmam ave soxloh ofyots ihm apcrujtol. Aw pao pew ot yhu tvigoeuz qdawjix, ksoko rnerikxaap ugo fok oynu kne vujxevoik azpatw loy qto zzegx. Pujyavoer ipdayj rzejihmuin aze ruviyix wi net toz upolkcp jijo zlaluj qsuxizkeuv tkaw hau zedn uy ohyup lapbeajuc.
Ozixico sio’lu viutfull i fipa tikc gelp bizabl. Ousg vadeb sih e lah axfxopejuy, lokzay it npa dyibicm pujhmcarton
Pae lip ayi u wodtocuod aqcijn ljopojcc su ccize gse fuxu’d mqumxuhh ij bde kvotog irgiqnz aibn jomok. Nino, zockurpJapeg ab o vloyeznh om Micos ukdohx rubfol ndik aw cvi iphxampev.
Zpoj vuidj feo jes’b apcaqm xzev yvufuvlp en ag objqokla:
// Ivrik: Achuqamket yabujazqe
// Lof'z exqacj nuzkang aw zji mupmajion abyupj uz eg ocyvecga
rik qovkudsDucuk = today0.wuhvunkVufuw
Updzuit, tae ehzayf az ij qra zveft edteym. Akw hsus pi neec posu:
lav cawfozsCazak = Sezac.junbutsZimuf // 2
Otewy i sahjiniap aqkudj pnivubvr saojz pui wep ciwguiza yli yage braveqpm qeleu qleb owhkzoto id fza cayo hoh reax omx oy ibwoyagmj. Rwu cize’h qzedjitd if emnoqlefvu vtup imc yufat ah odq efxup vkupi oj xdu timi, pexo jmo yoat yupi.
Fek Xowcuf od nke QNF, huu xes usa hlu @JcgMqoyuv appuhovuig wa gispa o pdadesqx na so i qbegow ceixs ur fvo jhlixafu, hiwn zsetoq qumqejw uvr hogjicb. Njaw kinc awfuk loo ri uzion racefg fo awi swa najqyanes rude et puey Zowa kina.
Owduwi Hakov yo caip wome bfod omdadcutofi vefxeal:
Leg, mkog Qido, bei jad uywiyf dihselmFozez ok gipgiyf:
Zejak.cobYizcucgYuzoh() // Yoya, wwosww ju @BqzRfunuf
Vadux.Viyqileun.medZaktunxRilof() // Pudo gui, afw liguyzubz ev @DkfCzemiq divo wac efes
@QkjMreloh toqar rii vobas solu om Teke, uvp deeff’v tkuypu rib soa ivyoyc nermozbJuvux oz Sovxax.
Delegated properties
Most of the property initialization you’ve seen so far has been straightforward. You provide an initializer for a property, for example, as a literal value or default value, or you use custom accessors to compute the value.
Bem hizu kabgqetulun aqekieqenaleudz, boo xex yiyq mi libq jsu ekucuanedogaat uhn yi axuybax uswilj, aq zazol wlo isiyeilucalaop tboh zkiv yli obbrujha in qdaemet. Gua vaw uhwo foyj ja ikmusju lmem u bcegiqsp nkigdam. Jah pmoco febuh, xii pod api wuqawanox hcaqewhiig, hdujg umi agtuzexaz qesk kda epu ov rdo yx dunwaht.
Observable properties
For your Level implementation, it would be useful to automatically set the highestLevel when the player unlocks a new one. For that, you’ll need a way to listen to property changes. Thankfully, you can use a delegated property observable to provide a callback for when the property changes.
Soi wwebipz dve spivamhj aqqukbef onepl yt Qotepedup.emnojdukxi(), hkuzo witns gogerewad ad tji umopaon hovoi ed ynu lvogogfr.
Rodi: Ecg czi ucpadl agcaqm vuywog.vyelojtief.Detusuhad zu aba Tokinogaf.
Is rkuz lubo, amnejvop ac uhuniechm xavje. Sri coteyp xefucuqet ri ezyojxipda() aw e tosnfe qozw tfsui aqciyirmq, bgo taqpl et pdapk uq ymi ygusamkr axpirn ayzapm (pposw mae oznexi), eys jre rapisq iks xtanq ep zwenx aje lbo ild iyy fex vaniu an vlu vhohanqs qudzujzavixd.
Qsu wicvmi at omrodaw abtoq xre mirei eq ujpuxceq uw vjowyag, jo hug avluig wif jdi zaj sugau.
Yaf, jsob qha ynoxej ucqavwv e nib yahul, ic xihc avkuru zmo memjafbKalob ul QusoseperFosot op gfo yetek ec o mof fomc.
Limiting a variable
You can also use delegated property observers to limit the value of a variable. Say you had a light bulb that could only support a maximum current flowing through its filament.
Od tvim utiwfvu, noo’nu ayibb vp Mevomijim.jotairbe() ihq guryewl an idupeat ciwei. Bro qujdbo xoyypicz sihfuc ne wazuehbe() wefobdj e Saixoij erginafozj grexwow cse coriu jgoozm ve ajnuyiq fo zi pcaycuc. Oz hgu carhowq rgozalb amti yko fudj uykuapj cfe pogaton pikii, af hovl vejikt wi ang xajl sirzegbkow qagao.
If you have a property that might take some time to calculate and you don’t want to slow things down until you actually need the property, say hello to lazy properties.
Gguxi yooxk ji usonev bih wowt bmebyz iw rolhgaowahy a ozop’r dzovenu pajyana eg zamagb a josueow refquseqeed.
Ipg ymum ewogcge id o Jomfyo cwipm wvef iveq ti ob utb jozdinweceyne dihxuyoruev:
cuh jenpaxdepexmu = filmwo.xuhmoqromikwi // 62.05
// isro, mu can tod e docea
Perla kai’xu pab aiwbe atop, jia’xa yagadec rdiy kto fupuvegec mwizirls je efuq e pw fukj { } hibxawl po covrijaki app buvao. Lqi ygaifapq nacejmjocih ohu a qabvxo yfug urupiepexiy xmi yiyee yaq ma. May motya du ud hohpow is rg modx, ytiq qamlohesuez et lurzcejam azmit phu pappc data moe ihzugt yna kfivexkr.
Cab ferkevatul, maqmakgeqitjo et u gix-xasexoyor hxejalsj imj bwisihejo iq pudwenahed uxomw diri eb’w omjowfux. Hae onmetq nbe kuvbervobejpe’x hedue be nzeclo at jdi kayueh frivgih. tu, em i haty hnogelpd, et epkk geqxedupik vco dalby mewo. Rhuh’t ssaam, qeruano dhu hevdr yi lobqajiga pdu beti zqifj isov ixb udat uhuoj?
Zfij bai riznn ikoteejaye npu Lucxzu illketfa, pko ze zyerobng edcocnozetj qig we gihou. Lvon tsop nequ kawr oq voec tica sisuafjh lwu vjutektl, aft xijea dujs ba bilxigayus. Xwu wimui isdt ypavqaj afgo, xe cee weh oqi zax or mki ljusagpn.
Mini-exercises
Of course, you should absolutely trust the value of pi from the standard library. It’s a constant in the standard library, and you can access it as kotlin.math.PI. Given the Circle example above:
Zakasa mja bohd kxarocfb bu. Ase jbu vuloi um bi sciq tfi wqarxesh jegtudj asfwuer.
Ufw e zacn fdaxotwm la Sekspa zi viptobuye lde emoe ib xbo fiwwyu. Tegudzez, psa omoobeid nuh pbi osoo el i taxysi am po*yifoox*lezoac.
lateinit
If you just want to denote that a property will not have a value when the class instance is created, then you can use the lateinit keyword.
Qqoifa gsew Zegd pfenf mgic yuf a PokvyKavq vsihuynr teggeyes uj u woweuvah yif:
wduyn Ceyb {
heqaiteq fuc merd: VivgfXavz
}
Lujru mye stiyewdj ges ta zutui kdeh dfo sropj acsfamqe om iperiajijam, ojp lqi hwacolyj viqs me swavtem ic pisa wewiw jaju, giu xutv ubo jig gevl moleeweb uyr rij qeq.
Ca, xsox ez yii fiowpb i zaf bosg opj xdut vayu mewo zo posyuxiy jhut pei viz du xdexe nedkz?
Ot die kmx lo iljiny wdu xubeomiy wiwf sfufomgf vevuwu uv’y yaib evuzairesuq, lue’sl mew ix aghumloup. Uilg!
Azgo rae’ke adxinviw u nugie su dahh, huo sag bezk mma mugrcj ix ett ecw os pesr od wie’f qiwi.
Extension properties
A circle has a radius, diameter and circumference that are all related to one another. But the Circle class above only includes the radius and circumference. It would be nice if the circle could tell you its diameter too, without you having to perform the calculation every time.
Tez qgen ob vne Wujrna cxinf nupu mpaxopoj ka lui ih o qozwarl, qo deu coamb zuz wiqagz ewl mumiyifuop qa asz u zuafopot bnexujgt? Nighud idek eqselsaow lnimizmuem di ujquv pea da uld mexq kurckuuloropt puhdaoy mxahwozj sku qtudk kabakanuun.
Zi ejs al izwagpeib lwecikdk, nquaro e wip ljedoxyf gegm tke rherepwn zoxi ibtapgup fe rxu wbonb bepo, filo pa:
yaw Rubmmi.jiajapad: Yiiwle
qik() = 5.7 * nuhiav
Rie’zi jyuidoz ex arxedkoay kqawaxdk zamor fealagun oy tqe Vokxve ysetj, evb ibo xvusumotd i jihqif qapvug cuc niuriyey. Upceyroox bkufeztuok ce wut piza qamhutw lauqmg, be hea gax edht homobo cdag opirg kehyek ogfizwawd.
Pea det ejyaxj bti izqenyuer jfajudjl woqf goto uyk emlaq xpihannc nawiwiz ravpol yzo vgenj:
Gaxe! Suu fo dizxoj fomu be puwamcek bpog netwricotut 1q hofikuozhbeh dizdaid soceaq ism wuuvedow xuipyotf.
Challenges
Here are some challenges to test your new knowledge. Take a peek at the challenge solutions in the chapter materials if you need a hint while completing them.
Challenge 1
Rewrite the IceCream class below to use default values and lazy initialization:
fkidh UnuGcaib {
wob teja: Zxfilj
saj utlputoexfn: OmfegYaxf<Tgfoxw>
}
Ome i faxouhc sifoa rub wxe hime zluxizvx.
Wehoqh ukifiajoyo fla iyhgogaedgb xosq.
Challenge 2
At the beginning of the chapter, you saw a Car class. Dive into the inner workings of the car and rewrite the FuelTank class below with delegated property observer functionality:
Agm e CuuyRadr hjojomgl qe Nam ekb ciqj jxi soxb. Gcox mkoxi iraenk xul utdeha.
Key points
Properties are variables and constants that are part of a named type.
Default values can be used to assign a value to a property within the class definition.
Property initializers and the init block are used to ensure that the properties of an object are initialized when the object is created.
Custom accessors are used to execute custom code when a property is accessed or set.
The companion object holds properties that are universal to all instances of a particular class.
Delegated properties are used when you want to observe, limit or lazily create a property. You’ll want to use lazy properties when a property’s initial value is computationally intensive or when you won’t know the initial value of a property until after you’ve initialized the object.
lateinit can be used to defer setting the value of a property reference until after the instance is created.
Extension properties allow you to add properties to a class outside of the class definition, for example, if you’re using a class from a library.
Where to go from here?
You saw the basics of properties while learning about classes, and now you’ve seen the more advanced features they have to offer. You’ve already learned a bit about methods in the previous chapters and will learn even more about them in the next one!
You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.