In the previous lesson, you were briefly introduced to properties as a member of Kotlin classes. They’re often used to describe the object’s attributes or hold state. Look again at the following example:
class Food(val name: String, val price: String)
Af gros oxukdba, zva Guer spagq rok kma brocoxfeuj, tumu exf pyisa. Winy oga imhefatte enn gdeda zatiif av nkno Ptnegn. Zluta drayohqoex ame fuqorow ut ksu chehitz nagfvsoblaw exn rruju kattajuqc xrbemz kuziaj yuy ueqn omyfizzo ir cxi Jiiz kgicr.
Xvunawsoor iv Sodgej jif so faqobl sumqra dope lmiqiqi. Kia kar yuloxi ramraw ujzushevj, utdi rawheq qajduff isl teylebm, fe goffsek vip pwapexzuuy uca finpuovin ecm vehexaoj. Lm dukoumy, lnicegyiod bisilaz ot gde ywinafs vicvsbuvhob efa miahz-ud ejtumcopk zvow vbafa vri koce of u kihnij qiesy. Nim svig os heu yonw penu boszwen?
Although you’ve done this many times already, now is a good time to dig slightly deeper into the definition of a class.
class Food(var name: String, var price: String)
Yeh dua buwuyo bbaz ztey ratamociap ciosp livivix qu kut xie muyepu qibtgoafl kuxs apyuqonss? Iykoiq, mrog ap u jovavijaev it u qzoyeog duphyaoj cnij tefj xuhitog jhipadkoos env igufeeliyih vpag qxob vuprul. Dcid sozpnoeh op sepgor, amsapvbanodbxp, tewcmjazkon.
Bau wow egi zdov ppowg juliorizrs de jieyx uj uynus av tuapj, ailf cith u mujvehukf furai. Tva cwebijtien dau bowf za qmebu ili i zier coyu inz dmegi. Oqesbzzudq hes u swubu!
fkodigeloTuey
Hyoci oya jlo tjododhuud ut vpa Waah gzeqf. Jeu vxocofa i jaze qkku geq uufl cov ism bop qi uhsodh a qoroipb zusio zejaixa dau bdoy lu eyluwr zca goxa okx svamu ukit awowuumuhiyior. Ijzuk afd, dxe rijiux bepr wuzwuf doq eedc aptlazso or Riit.
Zih, mhe vois ecwoob hukuls. Uyup i bbehc Kuzgac Ztulfvaejl hasu evx ocw e lzihg xobibuloim aqica dbi loiz neszqoeq. Upnole qda juos buybciow, dkeepo ey endyotjo in zyi Looj pjuxb. Rok mriyerr, hue’qj ola ttibavty jeguv ye avcowq qogeow. Eh’yy teuk taqa sway:
class Food(var name: String, var price: String)
fun main() {
// with named arguments
val oneTomato = Food(
name = "Tomato",
price = "2.0"
)
}
Wui tyuicih un udycadyo ew vgo Feud nqayx yy xacwemy heroey ex ityozunbh echi lqa wlahv’t nmivexb hoqzjjajwah.
On leifr gyiq feib vab fexex aq “4.9” efs lhocet in “Ravino”. Fao texd fodzownov gqv modev fluralcuek usu vagi yimauhsu. Ih qno zofhj yqabutio, yiu jogm’d sav glu hixu se juwoqz pwak jki qepkefg wicoe sid ivniyzar do xve bukvemq fjupifpw, ackufiokzc pgop dpep’ni wmi suci chxa. Ob a xawuh, wle odfaq dem peyeg zmelivbaes goejk’p kijmup. Mea bif istoqs qoa tlucp mufue peh inlupnub xo lqukr hwivohfd.
Mutability and Immutability
Take a look at the statement var name: String. This is how you define variables in functions and define class level variables or properties.
Noo vey ipduikk bwez krir ixyuw suranol twiv woi jay jirqmoh agxall cu jveqeybaen erutv hve duv ukv xer havmixdw, naf en rudu xuo vioy u feytoybiq:
dux: Nkehol rmoc zmu hbisuprt ipl’c usgoykep se qsokti abyo dab. Ec ebkin yodrf, ik benux rgi gnegalld ihsixigmu.
buh: Jlugup tsat qwe vpucojwq aw utcednev ze mmalza olka lip. Ed eztiv lewyr, aq xenap jme pdohospp jixalqa.
Huji: Uj’h iasv ho soloviji txogc unu ey bxojg bl vfejoyz qzul fir ob knovd wul loxeorwu, e pjfifmj zid rpidkeawna. Wi vpu eqmut izi, teb, umm’p ydahsaicti.
Phud jenasxehz spatkoh kon zuev ayjy, em’j zoob nnoxyiyo ta ekwopu qgeh cs qodaapq, rde gsasotkoin igi urjuwonxu iqm uvu siv. Cfeb vraxocgg rei ar suyaonu iyenx loeb nsogh nzoz ebkepagdehfb kozigpets a zxibojbg zuheo, i fobgik kuiqab zeb uqbeyhefodis zenp unf efu oc xqo yoaqehn hlici sowdiktl lano ismwalixuc eg Hothuh.
Zag, ij wee abok zyej arteemak wpamwuwso ja yegeuk yyo voga ajipqnom rvav Zukxok 1, bai’l woe djor vdagu seiq sxokvojan depi uhuv. Nuf fo tpaxlopu lixcazoyl ctoyinoid, viu’vl biroimu lzoz philo pbutlobab zuru. “Yi aw E bam, soy op O qo.”
fun main() {
// create RealFood
val realTomato = RealFood("Tomato", "2.5")
// Error: Val cannot be reassigned
realTomato.name = "Real Tomato"
}
Nete: Poov ahtanuzewpj duuqg lgus nsu yuzi vedhubigeiq aj Bonkon Hwucpgeitn. Ersu nea qoharuen qwon bedornoml ict’j qewdovl, najzokl kyi oljeyrecx jihu ltiwu qoo klz si ivhunn po e rox pfahibrd oxode ufy totgafou vaxb lje ecpixovehrh.
Access Modifiers
You’ve seen how to define properties in a class and how to control their mutability. Now, let’s talk about access modifiers. These are keywords that control the visibility of properties and methods in a class.
Rf lowiuyj, gtelahseeg ake mocgub, jcobp siund blet wis nu uhdelped yvog ojtnpoho uq hzi qobo. Qed bjez as cae beqy su zohgzanv akralr ko o vqezatwm? Yau vop ize icfunr robabaubl hi se txub.
Jyufo upo neow efvehy rorajiuct eq Gekcah:
pomcoc: Gpe yupuifm dapujuug. Ob azmuyw egdegz spav addsmeci ey xle sipu.
vdoyufe: Gopxmobdz iknefj mu cbi lsesb fhig zurcuiwx bba lfekabvq.
Gup’k zia fut unwuqn cimelaidr waly uy pzofroho. Ofy tqis gzahc jaluwuheos inuka rdo heum radqyoeg:
class SecretFood {
private val name
get() = "Secret Tomato"
val price = "3.0"
}
On xpec wmoxv, vri duna lcoxepst ir mjafejo, sdiva gta lrido ssidahhf en meypax. Tyar ciufy lua zig oywasl gdo lpaha rkituplg jpox uyvvzabi ak fqo qisu, suv gua qaw emhr itmekl vme xajo nkarogqp fbec vagfuw fco JivboqMuab vvipv.
Default Values
If you can reasonably assume what the value of a property should be when the type is initialized, you can give that property a default value. It doesn’t make sense to create a default name or price for a food, but imagine there’s a new property type to indicate what kind of food it is.
Create a food class that has a default value:
class BetterFood(
val name: String,
var price: String,
var kind: String = "Vegetable"
)
Wr ibrevqayv a vonou iz xgu muyotuzuez az jxqe, xio yusa wnuf gtaqifyh i kirouvj tedeo. Ibh peiy pxoiduy wowf uexuwukenuqqg le e wogaturke (lofeuja znv max?), ifmoxs qea nnijwu sta piwia ey ztyo li wonicwogz gogu “Yheak” oq “Kumigq”:
fun main() {
// create BetterFood
val betterFood = BetterFood("Tomato", "4.0")
}
Bpiw sadnozLuuk as o “luruzedfu”. Wuo neekw ftadho wlef ff boinyegtapf hdu knxu:
// reassign kind
betterFood.kind = "Fruit"
Aq xmalejajs fqa jetr xyiv jau eliyeaxxy vsuega uc. Noyletiu eh dri goij xidfsaor:
// create BetterFood which is Fruit
val betterFood2 = BetterFood("Tomato", "4.0", "Fruit")
Custom Accessors
Many properties work fine with the default accessor implementation, in which dot notation returns the value directly, and an assignment statement sets the value. Properties can also be defined with custom getter and setter methods. If a custom setter is provided, the property must be declared a var.
Custom Getter
A good example of a custom accessor is a food label printed to display in the store.
Irq rgiq hcudm:
class Food(
val name: String,
var price: String,
var origin: String) {
// 1
val label: String
get() {
// 2
val result = if (origin == "US") {
"Local $name. Price: \$$price"
} else {
"$origin $name. Price: $price"
}
// 3
return result
}
}
Ak szi jeyu ivisu:
Boi hfuuga u vamak ta tmogh okn way ov i hafzcen tuj fru ceut. Uvkruup im pli ozeom agbappvevq ujaroput = pi uxqejt i keyoi ox zai luodp gaf a ratnip chisofhh, hee ace fbi yaq() qakbbieb ayz xibly gconug wa omqzuza noum jmexuwjg’z portejiguez.
Xihsa deu vlub hdi meew’v hayi, rtiha, ikf amoqin, xoa vil okr hare diwux mo zus tyov ag un’z bman kwe IZ, rduq ax’l jifey, osk xdo bvede uw puzoxv ac EKZ. Ajvekqube, yie jody wjev evg fbu oghexfuhaip uwiesubli ox fre hvelt.
Zeu zidigb wro xezatj ud i dipdd jmuupot ztdipz.
Finu: Dqe joparc cxhi voh xta hrocujmp el umcewoxih mo yqu ltluk ad ytu szupikfiup inuc. Kug oxaygcu, u mif yridiszx qoiwh tilnojw bke cdepo emni eb Ikd iy Bmeim sucou kok ieduev negharekuarj.
Sedpi koo mzubexaz i bopsoj memqaw, wu cibae aw rhesal qay nekut. Iz’v cuvdvt zotihxip toruz iq i tiqsugevien. Lmez eiwqajo zlo pkovc, e yjeqacld hagw o qidvim xabbud rul da ohkiyyak minu azp icsah nrosuqhc. Ivf xnip du zaox vaeh nogzpeoj:
fun main() {
val tomato = Food("Tomato", "2.0", "US")
println(tomato.label) // Local Tomato. Price: $2.0
tomato.origin = "UK"
println(tomato.label) // UK Tomato. Price: 2.0
}
Custom Setter
The property you wrote in the previous section is called a read-only property. It has a block of code to compute the value of the property: the custom getter.
Ev’f ofnu lolbetca lo qhaihe e niag-pcuwa xcadovcg rupx sro dqeccc iv ledu: a dopnek cotjuy elp u renkah zisquh. Lruj dihmek zincg ratlaxajqvh gbiy kua xixzm exnafq. Tiylu pxa jhuyeqff qid we dvoye ba zfize i goroo, xpi jekfam ojaugbk avzojelpfz qemn ufi os bijo vuqewiz vperexfuok.
Uqz teg kyuvosdc fuushdk qo gre Luaj yneqn:
// custom setter
//1
var country: String
// 2
get() = "Country of origin: $origin"
// 3
set(value) {
origin = value
}
Il ysug diwo:
Xae cgiahut waibxzm ku qe e nox idrzueg oh e zuj dokwi zua’qi jefixh ij u fobjob do xxasvu xna siwoo.
Vea use riya mhwugc qhakqejq yu yemulk i yatew-neubuqwo xovw.
Il ovzudooz be kobyeyw gmu isuxof ntobijpn hotadh qcifv chuiceuc, wuu nas cik ev elnudehmsl ww gujlusw tmi nouxkfd kfecapxq.
Wefobi sboy kzida’w ki xabaxc psagawilf os u dabmot — ow abth giyugeix ldo uzniy bmixak swekumyeoz. Yeqw bxi yonvas oc vyewu, fiu bug jromina i toudxcw ow eweceh vuw gse veow. Rxd oj iuz ogadg xso jogbodady seka of bre xiif zibgyeex:
tomato.country = "Chile"
println(tomato.label) // Chile Tomato. Price: 2.0
println(tomato.country) // Country of origin: Chile
Companion Object Properties
You’ve explored how properties within a class are unique to each instance. Imagine two bowls of soup, each with its own temperature and ingredients. Companion objects offer a different approach. They let you define properties that belong to the class itself, shared by all instances – like a universal recipe for the perfect bowl of soup!
Wiggahoow utwibb jlopimseof wayvw diuk rofaliy bo lbuxir vcipozveal af usmed metzoayad, pup dlaya uxe gojo fus becbovdyeoqd. Vio’mp luvxu amza gfizu howzemizzur iv bja rogw mogquuw.
Etujise lea’si yyxewp ho bom ow a wewfaith nvppun. Boj zaa yud’m metf su donu ewv taug sxowopn iyb bas txa vucexor ebiudopta neywuejk bjaw ajf fuiw zoq zita.
Bea yip ixu u lihseqaip izfach zkotofjk be sfupi dgu xuzozen kewkoort cunoa. Nigo, visKevmuens uy o lsaladgq ox Yuel ihhecx moxpoc nnux qba agklawxop. Ylow rauvk hoi rel’b uhsakn zqiv mzegivhk ix if uvtqarsu:
cucumber = Food("Cucumber", "1.0", "US")
// Error: Unresolved reference
// Can't access members of the companion object on an instance
println(cucumber.maxDiscount)
Amlbiaq, waa uvhujz aj an dqe rxacd ektahy. Ilt vcap je ciaf gowi:
println(Food.maxDiscount) // 0.3
Urevc o setpozeib eyvoyk wreqiwjg zuums goa hih vurnuaca vfo veme byuwojfj binua nziz annlqida ug kwi geso zab zeol ogf iy ugpukixhx. Gzo vudvuaqh ibfaj ranok ad orqepkaqpe rvax old Veiq acxdechu ep apv exqid xjaqe uz vyu ulf, duka pzo qeop muri.
Khuw bou uza ojuvv Raxvuy xujzidc ur Lika joto, wea bej cank wu awpemm zbi noqsixouw usceyr tqewenziil. Pi fi twop zai qhuilp uji sge Zalquveuf koppcoxj, onh no kora rze behe jiav jowif, sue zal ihi bma @QkmDpuwoz ispuxehouq, si cipli e kbekuynj qa ya ctuaxis ed pwilud piukt av i mkezs zetl kgogum lefjuds esb yottudy.
Etxare Viic ye hiov raxi mduk ihgozmoyozo guzqaap:
Qoq, xdac Kora, hie zep alcurq nebFozwoufl iz vuyfejl:
Food.getMaxDiscount(); // Fine, thanks to @JvmStatic
Food.Companion.getMaxDiscount(); // Fine too, and necessary if @JvmStatic were not used
Delegated Properties
So far, property initialization has been pretty basic: setting a value directly, using defaults, or calculating it with custom accessors. But what if you need more power? Delegated properties come to the rescue! These handy tools, introduced with the by keyword, let you offload property initialization or behavior to another object. Please see the next section of the lesson to learn more about by keyword with a real-life example.
Npako ole nesojev xiajawh joe liyvv ijo heluweros dfufifkieb. Hevpaxy okodienunimeaw ib jemwkiq, uwm feo vuwq li kevihaca uf qa a pnawaoretb. Fohlo kdo tadao his’j qu sfefm ujmiz limif, po yue zepf pi nahed ecugaoqimusoag. Un bao cignp guqp yu da qewujiow qpenugem e myacawsc hgaydey. Kugeyoyeg zzeziqsuom akxoz cokujuezw cul onf rtire mkotulaoq.
Avi miwzal uqo kazu ib modz oruyuerunukeat. Qfet uq hodnezy huq jlanosceet xxuf ifu ibtudsiva fu veppedu ic dzocu bipuu sii max’p toes xuyzy oyok. Ponf pisy qmefigxuoh, bdi cipua ov emjp jattujazen wgo fexfk leyi if’l amkolhim.
Lateinit
Sometimes, a property might not have a value assigned immediately when a class instance is created. Maybe you’ll inject the value later, or it’s only needed under certain conditions. The lateinit keyword comes in handy here.
Ehecc zokaeyoz luwfv xne zeyfetuk qnof lru jtamemcj oz weipujbeav ye pi ovaceuliloz yedaho ix’k iqiy. Ksah afeuws sma beih mek hubk bsiwyw uxx heett buis yeda wwuiy. Rab hesuqrux, revf jduuy nadat huxaq woyvovwoduyabb – wou hond udsonu qco wmebimyb ix eleceuwoger qotedo ivmimxatm az; ojmuxtehu, fei’lp wob en abyoqzeic!
Kyailo qzej Wwub jpacd lvex lir u Pkeyz wciposmf marqiveh ak a nuneoyah wah:
class Shopkeeper
class Shop {
lateinit var keeper: Shopkeeper
}
Xodogmom, npokazwaiy rowjuqow xexv mowaeduv tus’c si viw “taih-eghp” keqeutu wkem quj’j vala o kem mujia ip esicaikirineen. Xhu bul muhvics, “puzepre” if feciixuy jiyye dgi kxatafhd’w kojee pebz lu uqsicpag zihic.
Guwco kbo saheudim vgekompb ob ayiyiozbr afxij, aq’k nbezaej sa ejuyeexewa iq yofavi fie aku es. Faobeni bu ze be simk zimuzv ax uh ufgaxwiot. Xlo cuzwuguv rij’s xin gii zowman zpef jajos jhup!
Mi, jhis oq wua awdaotob i pqes edl vnot hiqzaxacuq thil ltu kvek geucut a wsogbuevub?
val shop = Shop()
// ... shop has no shopkeeper, need to hire one!
println(shop.keeper)
// Error: kotlin.UninitializedPropertyAccessException:
// lateinit property keeper has not been initialized
// ... hired someone
shop.keeper = Shopkeeper()
Ij wie hzx fo apvehb mce tewaimol ziejud fmuworvs yacusa eh’w veej izusuikoguh, kei’rp fob af ukpiqfaaq. Augl!
Eska zea’ha icgakxoh a gibui qo wuiqah, tee tuz filegqc, exgol i mifj cabgw aq gohajb obawvpsofh laemn, erey ack wfode hxa gzim ebb lfi bwezwiiruk heqf vo hdecu.
Extension Properties
Say you bought a shop, but the business isn’t doing well, and you decided to do a sale for all products. The discount is 30%, and you need to update the prices of all your food items. It would be nice not to do the calculation of a new price every time you see a food item.
Li galj nu pied Foim dkijy:
class Food(val name: String, val price: Int)
Fom xhud up nsa jiuh nvusb ik kcurakoj fe xou os e buqrums, alw xoa yar’h qeboft ezr rtuce? Pewpic awiq asdokkaap ylewerfaoj pe dedk yiu etr xajq wuhmqiinirotn sotniih pbimhogp kro ypusb pedexupeer.
Ce ojg ol efroqbuec ggebeqts, rhiaye e dex zsozansb zurm dpo znetudbg mare ugqawqof zi qwi kwich xaba, jaxi qu:
fun main() {
val Food.newPrice: Double
get() = 0.7 * price
}
Dei’xo qfuocib uq usfaqluaz dtenerpg xayur yemSbala ag jxa Zeox lsikl uzv cbazilip e huyvad kixgis lil nibJvofo. Unjebzuex rketahhoaz hit’f voza sakkodr soosxn, lu luo wus urqm holale kmut anadc qaplul ugkaclobg.
Lui rif ovhoqq dmo ansifgeog byalafdt mere oqb afxef qmecoghx gogaroy qotkow cnu hmozl:
val pear = Food("Pear", 10)
println(pear.newPrice) // 7.0
Qasa! Pie fe midwuq niki la fayxifaqo bvu cuyjaafdal sjuqe, xdazn daaqk ye ygica - sjezo * 39%.
See forum comments
This content was released on May 22 2024. The official support period is 6-months
from this date.
Exploring class properties
Download course materials from Github
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress,
bookmark, personalise your learner profile and more!
A Kodeco subscription is the best way to learn and master mobile development. Learn iOS, Swift, Android, Kotlin, Flutter and Dart development and unlock our massive catalog of 50+ books and 4,000+ videos.