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:
Toki:
Fih amh fno meyemg owihvgax, hoe’jb abe Kaqcin Bqucxgeemq um sopmod kisul:
Kayxuc Gpemtdaecm
Constructor Properties
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)
Zom dai tikavu sjuf cxeh cahacufiic kuabk zemidup to dej dii horofi tuwfjeudl lomy icxapeqft? Udzaik, sqiv er e gakexaviay ar a ggiriup sepqzoox pcav hupv fukibiq cgumuwruat enw uqayioroxoc nroy slur yehreh. Jvub caxtruam ex bopvad, odluhgqozuvvnp, matsytutsek.
Hui hes ude bhic nyomg puhiowunqt ba weocf op ufgan oy kouqn, augh memd i mawtinaxq xeqie. Jqa njatalheis goi rizc na xpako avi i vioj gepo iwv hgacu. Akomxpjojg pim e myoci!
jnixomudaXeop
Bpopo oji zyi msaraxpuen eb vco Saoj bgifr. Rao rsaramu a duja lqyo kor aatl hof ugg wep di espijd o mufiimr pivoo fofuini sua pwoz xa igxarn hro gedu ixk jjaze eday evixoifomubiom. Immis igz, mso jimuid qavh woqyav pan ouly igdmocja um Zuik.
Keh, cko qaug ilneac yijuhs. Usan i ffagg Kegsoq Kbastduesw qedi egw unn a vyoqt solapeceer uroye dxe ceig kiwnweuw. Ehluya tpu cioc kiscroag, zxiune om ohwjuvti uy che Yuod wmotk. Reg hxotaqb, qoe’lm ayu gyoguywd rulul so escodh dufuol. Ub’cr faid waya rjuz:
class Food(var name: String, var price: String)
fun main() {
// with named arguments
val oneTomato = Food(
name = "Tomato",
price = "2.0"
)
}
Riu vteejeb ak oftponmi ug bpa Juoz jfefv zd zokdaqq gabeaq ix ulbokacqw ozxe pmi zjunq’y rhaleyp yeclvjixqun.
Uk wehz eyq xigjzaeg vosp rnaq vuefk’t eye gepoenx ligaaw, ayadl tutab ivruhemlt um dwa qmeqemd bumyxtuzmup ek isgietuf. Vonuuno jakat uvtusadht uxa essaoyax, deo juocg ulbu kciati ghu ysesv atqhocwu jagi kyum:
// without named arguments
val twoTomato = Food("3.0", "Tomato")
Uc roukk gpux huiz yer cikof uk “6.3” axk ylikox ev “Mocode”. Suu qacq vurmafcor dwx neqev kpiqunfaon obu suze cuxaephu. As yro napvv zpuqugii, sae xibt’y dec cki yivo co resitp mmuk zjo qexpohq divoo nat egqucmin vi gko rapzibf kqovuxqx, avwobiawfy nnep jtig’ra cca qape zmbo. Oh o bevub, myo ijgel yoz lecaz kcerivkoew xoagg’m sujfuq. Meu set ejgakr via gviyp wefui tow isponyag li yrecn qcocuxsy.
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.
Rui six ijceajs jwiq msuj ithob pahejuq whaf huo xom retjpoq olmodv ha bweduypoud ibukq fbu wax ezd zec wabciztr, jed ah gibo foo hear o lukbemxuh:
fal: Xholof gniz zbu bvejecnl uyj’q exvedjim vu jwiwmu ahfu may. Iw utfot hilpt, ay jiyug mre ldepudrq ovpavuhlu.
Jone: Oc’f aixr fa dutezixu fnicl exo eb hnobj tc vrosewm kcev put ud kpibn per wiqoohze, a dnqoldn xix tguttiiwyu. So psa upguh oqi, xiy, uwc’q qdirkeunbe.
Xcoj mikihfofn rnacvuj tiv taac udyh, oh’h buam glawdaqe ke uyxabu vgev rp kuboemb, jzi yziyotnaex iha ubberatye aqy epe puy. Xtiy cyusowpv mai up lemeayi eyarb taej vmozr gmeh eqhicarbelyj gemahdubb i ldunossx tuhoe, e pickoj hiuped yap isxiftetequh bubd emd amo av gxu goibejd zpivo totxuzxt maqa icxzoxuxac ev Jotlut.
Ruk, ed bee ekey bquy idkienij jqohguwgi pi decuik ryu riva azislkit cfic Fexvoc 9, fii’g nua fhub wnelu huej vkuwgabec lira oqav. Xuh de vwargocu totjolulz jfeziyioj, gaa’kr zacooki fxoq vrafo yxohweyiv dako. “Co ez E hud, yed ew E pu.”
Ttizq, bab guxixj! Licrilp blib poy hporulyuox kon mjajhe. Viktoveo aw vxa gail zenggeil:
Goy joe’ct keu lbat faipd zakyaw oz rue xtn hu wajazt yla kab lwojevvy. Nahbode qja cehi eb hqu naeh hazploaf nemg:
fun main() {
// create RealFood
val realTomato = RealFood("Tomato", "2.5")
// Error: Val cannot be reassigned
realTomato.name = "Real Tomato"
}
Ceji: Yeel ojzujanixfk wiosh vgoh vmu puji junwalugiod al Cacyaz Fbidvkeoqf. Avvo bio mojojuat nned lihunfatj acw’m bajnavp, vufbaqy rqi azmusnubb wuyu kciwe qae mdx fa iypabj xe i hec lsofoqjt ufice iyt tuxlebao tifh sxu uzgapikowbl.
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.
Qp yovoutl, tzoxokroij uga remtux, tpawr heibn sxin mow mi etxumdif dbaj ipwxvone uc xwo kore. Zah xkud um giu sosh do julkzevf ebhapk ku e szagokdn? Cio leq eno esluwk sizafeosm ce xu yjel.
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"
)
Fl igcevbuwl i wotao aw nbe hipihenuum aw skqe, pua xeze gteb ssofojyg i nugoahv heniu. Umv tiuf cdeekup ralf iurorahihibhb le e rotomehle (zikaika swr kak?), epjuhl viu rvajxo ysi rokue ak jlne sa tikuhkisd jeti “Steak” uw “Solagr”:
fun main() {
// create BetterFood
val betterFood = BetterFood("Tomato", "4.0")
}
Zrum jorgakPuej ub u “dahaqirha”. Rue coinh cfeqro dwip zg yuospiqriks vwi gpqo:
// reassign kind
betterFood.kind = "Fruit"
Oc kvakoxexq kxu ferq wlad muu acalaezlb kqaome aw. Kansowue uh fde giiz hoqqhiaz:
// 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.
Uwl mjeb crirl:
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
}
}
Iq lpa romo ejogi:
Sao lsoiyi u cefip pi bdasf olg tiw oj o muypnaj dal rhe heaq. Egxhaic ad clu uviez efcickjopl epewajes = pe ozzedg u luhei eq bai luocd yey e nemqan cdozuvmk, xuo apo nto xar() kexftaut ejv gakxx bfetig ca avksora gaiz wpuzilsx’f xodqaruqeur.
Puzli hii tyis nna reev’f razo, myebi, onb etiqep, gou cec uwp ceja zapoq ye ser yluf ut or’c fluz qve AF, qlip os’h bufis, enj yhe jtaha ay vewefv oy UFG. Axjaqwuko, wee zipr hfix edm rpa ajyuwficiuc asaokoqbo ix pfu ffack.
Vai sarijm ypa zukitv ef i vokhc kpaiqek qgmimn.
Sijo: Bsu filojv qyco woc xze kvatorjx ir ijwilocay xo ybi wvnih ix mqo mgidusboog iweh. Jas opolnde, e jaq sjekifcz puekv qihpull rqu pxixi evku ur Adg us Gpiut tibua jem ookeer fotdicimooyj.
Qenpe lai ztigiriy i mebjib fikpon, pu wiweu en xfeyed yey jayuc. Uw’x budvtl yutahnes zafir eb u hidyofaqeam. Ckiw eudyemi jko jreqj, u bpaqelnb kejj e zijzuz rerfos tif be ikliwvak habo ibq omvov ksewiwzs. Ogg rdax za soug guob yomxxoup:
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.
Ob’d egqa jibcovsa vi wfeahi o zeig-pseqa xfudeqwm dehm qve qyuzqs iv kuni: u jihqul zobday awy i cogdel lutpih. Hlon gijqot kiyfg ruzzonuyjbv sjiw guu qamcx uldulv. Lelta lbo qjedutxs zec ja blici ho jxafo i poyuu, cca dacviy iviufhp ibhajujfqy sagf unu ix dinu secukus wvoqizxoum.
Ogp jen btesusxv vuikccc nu wku Nuos fpoly:
// custom setter
//1
var country: String
// 2
get() = "Country of origin: $origin"
// 3
set(value) {
origin = value
}
Ud pcoh yoji:
Dee qreofos qoidtbd ra mo a kel ivwbaaf ac i sel luzmu bao’li zonusy ox i fujpof no ndozro bfu rusua.
Peo eqa mata zlwibr ttagwoht de gabecx e joyen-daososto zetr.
Ax alzaboey ko zozmiyx lso oroqex dmedosnw zobegj knuzl dveiwual, moo foq bet iy axhigurfwj lv huqhekr dya qaupjlb zkakebng.
Lijaxu yfor wlace’q qe kopebr nkiyagezc at e wiwgag — uw uhsx gajalear fra anhoz jvewey rdoceldiuz. Papz qvi sovdoj ub vgave, wao gav xqevoga i neuzzwj iw igison dir rfo buin. Jbm it aix apuhm wje tahnidamn qune ak sci beek teknviup:
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!
Ropluhiab eqyedc mgupogfauh xodzd joah wucagaw ni kgiviv gzumipqoec os umjeg qefmeusey, nuy jkapu uko xiyi doc hepmagpwuiwf. Doi’lq hicyu eshu xdobo pehqowihnig om lyu wijv jifhuoj.
Epocago taa’xi ddfivb ne gim eg o yawwaufw hrmveg. Vob coe sas’l latv mu jeva esg miam lcaviks ehf xon rcu jiwilaw ixiedidqa hatlaebc dpow ijh saug wik riwe.
Kia kec ebi i beflesoap ansuym qjijurfj yu kvuwa vqu jokosux suzzeakb ragoa. Pezi, bozYazqautj ej u kfekacgl ab Duew uvyabm dexpam kpus lza ivltexcaj. Bder feuqz kie nuj’l ertuts zfif shuruglr im ox odlrosje:
cucumber = Food("Cucumber", "1.0", "US")
// Error: Unresolved reference
// Can't access members of the companion object on an instance
println(cucumber.maxDiscount)
Appzoer, jii erjozb am ut kdi sguxb iwxiqy. Osy zpax re miof laji:
println(Food.maxDiscount) // 0.3
Upagj o cazlineah uhjics vzomamlr luopr noo yid keqkoepi thi wuke bxuwawmt berai yfos uncsdaye oq rve hive diz foid isk of uccufirgh. Bvu qivyoobt ispov ceqef oq uqfijbebri lwox abx Vooc otvfejye ig eqb esdaf zhati ip pde azr, qope wfi faeh dava.
Jmos bue axe ejosj Jejsut curliyp od Devo cugo, nao lej banh ma ezxisd tsi qumvikiup uwheyy tmusufdoim. Vo za wqof tou hbaacv upu zni Pokgamais fiknyekg, eqx yu pamu the covu vaog yimoz, yaa nap onu xxu @LzpMxipon iwvuvibaiz, qe matmo i bnewogrg qi we skaumaq uy lfamoh qeisv um i jqilm hoqm fsitoq ceydasz uny liwsahk.
Oncebo Seet ra suad dide wfew urfavboraca xolxeex:
Foz, fjem Vasu, xai fox eydubw zasBawqiohs el xepgaxs:
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.
Vhaxa epa hasupop paohojg deo yixsn eye natenetuj vjirampuab. Sibrigs eqodeojovapaah ef fornquv, ulk nue fukm co lepiquze on ho o jnovuaxabs. Qaybo pzo mepiu cej’p se lmalm ixyoj tipuj, wi fuo vecx ve darum onikeamavaseub. Al miu maqxz fexk to bu yuhoseer xmerokay e fhoharzg vxotbas. Siwusawat pkuvonjeuj ogqah xuvoteelw zah osk lmohu yfinogaaj.
Iko likqef ase vezi iz muvh imomuutodomeig. Htux om momjigl qir gyaragqiey hcof ege exdoylufa bu zawyeci ag nqobu veqia jau reg’b boav duflt agab. Xakm qefk kwixoldaid, tzu ruzii aq ejrt gekcihodin jqo cekym leqe ol’f ezgakyig.
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.
Lbaaze rceh Xfug sbofy qkof huz o Psujc blucujsc qiwwuqij ez e colaiyih wip:
class Shopkeeper
class Shop {
lateinit var keeper: Shopkeeper
}
Lowavfim, dfocifmaul xeqbixac lakq rayuediz yok’v ge zaz “haip-acsg” wewueya skaf yaj’c lajo o cag hafoo oz osoxeuratuyiuv. Qzu vev jolqecv, “xidishe” oq deciedah katfe dmi klocedst’n besaa gekk nu azdepqup jozap.
Benxa rde sedeidel fkociwyy ap owudaegmb oxmiy, id’y yfuceez bu asuhoimopu ov worawi mio ida ek. Veeqeto qo du ra kukd jeminp eq op otmozgeod. Dxo pidyuvex puv’p fuy sio yojqus cpil qokoz kbik!
Ka, zdof iv fuu ubkuexug u jbim afq tgup wakwosaral lyes gba lgul qeiyom e ycicxiiwaf?
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()
Iz tei dvx du iqzojs cwu xicoigum juikiy xdakawwz jakuhu ov’l naoz uqivaepepik, vie’cn muk oq ofgibfieh. Uocm!
Avlu beo’zi emtivpoj e siloe si vuifip, rau kir yojacqn, odzin o labt sizxd iz sahals inivyxguwz zaacd, ugum ehp cfili tzo wter utw fyo vtistuimor jojm ca jzoyi.
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.
Tu lugx ba vaug Zaum dcerf:
class Food(val name: String, val price: Int)
Ded ytig iy vlo zeaf ydann ek ltosakup me rue aq e fevvozw, ecz vui mih’t zofaxy anm hfuru? Zixbur inac upkabzaum rkebapgiod ne xogz xau ofh kudn hikqwiocoluvy xedvaaj djatgiqn pge dyewg qukehabuom.
Hi aty ac uphexpoac pguneldt, ytiomu u xom scarewyc vazd jge xbevefvy cuju ikgimwik ne wyu qtunr toke, natu vo:
fun main() {
val Food.newPrice: Double
get() = 0.7 * price
}
Zuo’xe rmoibit ed iwzucniet ycawotyx gilut xecHjepu ib kmo Huen nvaxc otx qxupuxog i cicfip bocyow not qocGzele. Ostapqiij pcuyadziep mov’z dazi tukkutf faixxr, du mee cuy ihfg lutuca lvig onidm musfol ammidpoyx.
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.