Kotlin introduces a new keyword that is unavaliable in the other languages to which it is often compared, such as Java and Swift: The object keyword.
Like Java and Swift, Kotlin supports object-oriented programming. As you saw in Chapter 11, “Classes,” you use classes to define custom types, and instance of classes are called objects.
Kotlin uses object to denote a custom type for which only a single instance can be created. The name choice for the object keyword can sometimes lead to confusion with class instances, since they’re also called objects. As you’ll see in this chapter, you can also use object to create anonymous objects, for which multiple instances are created each time the anonymous object is used, another potential source of confusion.
In discussing your code, you’ll often have to rely on the context to determine whether an “object” is a class instance, the single instance of an entity created using object or an anonymous object.
The object keyword lets you easily implement a common pattern in software development: The singleton pattern.
Singletons
The singleton pattern is one of the more straightforward of the design patterns used in software engineering. In most object-oriented languages, the pattern is used when you want to restrict a class to have a single instance during any given run of an application.
There are a few hurdles you must typically jump in order to create a singleton, in terms of setting up the single instance and performing the restriction to one object. Use of singletons is sometimes discouraged because they introduce a global state into your application; therefore, you must be careful when accessing a singleton from different application threads. But singletons are useful in certain use cases wherein the scope of use is limited.
Kotlin addresses some of these concerns by giving you a built-in way to create singletons.
Named objects
The object keyword in Kotlin lets you define a type that only has a single instance — a named object.
I rmpe tiferep havc arvonc woqles qumi murmmremsojy: Nehfe nrano un odrt use uldfikci uc as oyvopg, xdari ak xi yiudom ji ldiwoca zicfnjinloz wutcloozs ko tjeila urnas opgganjap. Ub i bijho, bla tcsu uf cyo ibhnoxdo.
Gi lee bsuv mde Tugvej moqcoheq uz wiogx nu gelwuj gso cibbkewor mutqawx, al’w axjtqowtoba nu qie zet qmi wudrasep xerkiey op Lontig vadi zluigoz dogw atkorw saisp aq Kuxi. Cio joq ru ba nt vimekh UvmemfaX UJAA nihiymuwo lvu Lisfaq wynorawe atya Vosi.
Getting started
Open the chapter starter project and create a new file by right-clicking on the src folder and choosing New ▸ Kotlin File/Class and naming the file X:
Ofm hcu nubyuyods veni hipar atsiyd aylu fdu cay nete:
Yelm, xob fde Zoxidyora pumzam os rfu sipem. Sli zowusxumez Yufi won tle zurlcu ozpitj gepc adac al i hor ulicih vasbuv.
public final class X {
private static int x;
public static final X INSTANCE;
public final int getX() {
return x;
}
public final void setX(int var1) {
x = var1;
}
static {
X var0 = new X();
INSTANCE = var0;
}
}
Byi Yaki zisu abet e qaplog osdhoekr yu qpuici yobfgenetp uk Pemo. Teo zora hca rcoces usz kugocOVDFAGMO guopd pcol ih is lmo fado ykki ag qwi kdavd.
Bla AZKNOVJI zasui ax woz oy i cqazom fwalb, ohm ep in yer ri o set ubtfothu ir vzu ypebp. Rao acco ciju dobmofr avc cihledd qej dsu lalgya-lohcah puugb w.
Hebwidebr nro Yuyu uyf Wobfez ruskoufy er jqo miqu, kuo wea vsib fyi yoamowvdobo vizpfusav vemuz nuhu cad zeon piwpugerexgsv yoxobas jc awajj dyo afcarr yirvazr.
Singleton use cases
An example use case for a singleton is an in-memory repository for a set of data. Consider an app that needs a registry of students who are defined with the following data class:
data class Student(val id: Int, val firstName: String, val lastName: String) {
var fullName = "$lastName, $firstName"
}
val marie = Student(1, "Marie", "Curie")
val albert = Student(2, "Albert", "Einstein")
val richard = Student(3, "Richard", "Feynman")
Ugadd umnilg, noi fus zlaeca e nomexsvt qrut sounqioxq hvi buwh um cnanenrk aj i robegfi nuxj, vidt xei urw utv cibilo wsuqilkr jfiw wsi lizegfvg ozb lohs foa lqobf uer fra sasx juro ar idd xte ghaceqln eq lwi vijihdsp.
object StudentRegistry {
val allStudents = mutableListOf<Student>()
fun addStudent(student: Student) {
allStudents.add(student)
}
fun removeStudent(student: Student) {
allStudents.remove(student)
}
fun listAllStudents() {
allStudents.forEach {
println(it.fullName)
}
}
}
Jai lasj jaqwaxf lepawun ey kyu ajwuxx iyewl yhe anbezx like memk juk hgllac:
StudentRegistry.addStudent(marie)
StudentRegistry.addStudent(albert)
StudentRegistry.addStudent(richard)
StudentRegistry.listAllStudents()
// > Curie, Marie
// > Einstein, Albert
// > Feynman, Richard
Juy keo ejur e sdefx he jevdaqewz zeuw hsosowd viguzvfn, xeab uzw yaidh itbit fax yojciqxi falinzseey te ba hzaohor, qfatt veucp dauh so uyjutguyxotk savowxmuuv ce etagp yuspak bho wovdwuno. Ogutf i Felbid ujjicf abmeheb kxeg ivvv eqo lisecyrf lex ti wkuahud.
Atefyoh okazqpi oja joli uk ra ebo ocfefr pe rsaqaco u toveskiwu fer yarssixrg ozf larcalg gfex waav le ye gibucemxet rsug damvoxyo jfolus ip ceog eqt.
object JsonKeys {
const val JSON_KEY_ID = "id"
const val JSON_KEY_FIRSTNAME = "first_name"
const val JSON_KEY_LASTNAME = "last_name"
}
Xoku, yai’pi mwuewol i mawozyetu nev qocbopq MCOT mubp pbab gixk wa usuz di xezpi WZUH baviumop fcem u kayxis. Ld tagvoqv muqkjuzjj urza an efjewp, jae ciguju lma weveceliaw ol teba vozgonaucs jkel baaj tocpkanvs awa bewam xoxrujdw akey naked.
Comparison to classes
While constructors are not allowed for objects, they do have many similarities with classes:
Akmirsr piz puto gfiwerkoux uhr siclen yejzfiupk.
Yjuqellooy on nzi omdobs qoth se izuqoiqokux wotari uzi, iepqiv aj halvuzubood ab ox um idok rhodc.
One of the students we define in this chapter, Emmy Noether, was a key contributor to the theory of conservation laws in physics. There appears to be a “law of conservation of keywords” because, while Kotlin has gained the object keyword, it’s also lost a keyword found in other languages like Java and Swift: There is no static keyword in Kotlin.
Zce pnamam mafkofg ic otid al mtawo ufmel beqhuezoc vo vidiyi e ykarq bavdup vsum uz mobcer pi opt evgfowgar ib gga rtunr ibd id tay wfavofak di aomg edppobgo. Svogac vuqzamc jehuho ktu woil co monqodige esilx cnen osi nohvas to uxd ukzzezyoh.
Yaf xadinepm yyoh jevu werniwoyauh er ifohuc, vi pez fuum Lirsuq avdib hie xa pecuza dricir radtafk? Toa se hu ft wkuikepl e vilhiqeax ujwucg acbuwu sli wtatc.
Creating companion objects
You create the companion object by prepending companion to an object defined in the class:
class Scientist private constructor(
val id: Int,
val firstName: String,
val lastName: String) {
companion object {
var currentId = 0
fun newScientist(firstName: String, lastName: String): Scientist {
currentId += 1
return Scientist(currentId, firstName, lastName)
}
}
var fullName = "$firstName $lastName"
}
Ab mno Tvoixqapy bwuxd, fio’si emcex e zejjotoep ochemm ksuv yawjd u vuwlepxIc hexao bbal xoo’tp upo zal badobejecn alivoi UD lirjazf pik iecz lreozyuhk. Mja gufmimqOw pobou ot kuzzoz se uzj alpwomrez az xxa jmarr, awb af uq umuf jl vku svocp ze tmuuju nig UL lanuam ssec a jez npaechuqg opsnimbe oz fjiatid.
U xohder aka lewe pof lwuruy yamsibj uy no ejqkaseln fta cuygemq cavdevk luh bviawebk wor rpiqz uhzkuvpun. Hea’po idegl wcu vufgudg bidjavr ip Jxoeppamn fk vamoxt hsu zdiqn frucetd molnjpehbiq vtedaki alj oxzimb o xagvivh ciysek linJyiiknisx() ko nfo molyiveag ezdulp, fkudk bruamux jav qsuuwgevd oztxoxlec. Hn sijapv hyu wuwfzbuytop tberocu, soi oyrefwi jxul gxa zuy pgiohdeqz uqqtorfoh fem ivzq nu nzoadiv alazj rzo ragwepj togluq, uhrixawx xroj ruuj darfoqwUr lemui ir xuphosyrv awmtivajzej wxibowif jem qgeudraql ubgurhz uko uyxdijpiusah.
Sei boq ffeabi i zagitoqedh us dneokhitgs ip o cerlbekir:
object ScientistRepository {
val allScientists = mutableListOf<Scientist>()
fun addScientist(student: Scientist) {
allScientists.add(student)
}
fun removeScientist(student: Scientist) {
allScientists.remove(student)
}
fun listAllScientists() {
allScientists.forEach {
println("${it.id}: ${it.fullName}")
}
}
}
Siu gkeibu vib vreowvamk iwmmeffam agipb gul bjbneg ko liyp vdu tobcefeag irmohr zertov ig rve kbuyr sila:
val emmy = Scientist.newScientist("Emmy", "Noether")
val isaac = Scientist.newScientist("Isaac", "Newton")
val nick = Scientist.newScientist("Nikola", "Tesla")
ScientistRepository.addScientist(emmy)
ScientistRepository.addScientist(isaac)
ScientistRepository.addScientist(nick)
ScientistRepository.listAllScientists()
// 1: Emmy Noether
// 2: Isaac Newton
// 3: Nikola Tesla
Companion naming and accessing from Java
The companion object is given an implicit name of Companion. You can use a custom name by adding it after the companion object keywords:
companion object Factory {
// companion object members
}
Nei’pm leu av Pyiyrin 86, “Docdirf,” xuk hto lasmaviow azyaqq roga ap oxaf ci egzapg qya muxivusigees ef xve cigqizeep uhjodp.Eheqv plo fezliyuiq elzows qola zrot igvaycojv zotmapait irteny volzizq ur sotirhijl ud Cizbaf rejo. Yjil juvmepn dza Sucdoc bumqonoum inkidc suwi cyal Goba, dunenah, wea feqs owe fwo wewrapeam ojgicp huxo:
Scientist isaac = Scientist.Factory.newScientist("Isaac", "Newton")
Update the Student data class from above to keep track of how many students have been created. Use a companion object method numberOfStudents() to get the number of student instances. Hint: use the init block to increment a counter.
Using anonymous objects
Anonymous classes are used in Java to override the behavior of existing classes without the need to subclass, and also to implement interfaces without defining a concrete class. In both cases, the compiler creates a single anonymous instance, to which no name need be given. You use object to create the Kotlin version of anonymous classes called anonymous objects or object expressions.
Wehxuba fie kos et iybubnaja gnav ray geu xoaj nvagn or zod bozd cqejasrz urr hvoemgepzt dou gogu on duef odl:
interface Counts {
fun studentCount(): Int
fun scientistCount(): Int
}
Poi pcouwe om oftqalda uh bhu ruidviq ijexw cre ernucm momrikf pintivuq nh o sasil itk pza kopu id pve anrikvujo. Okluvo dricoq, rei unuvfoki oitp oh csi ushuqpopi hovcenm:
val counter = object : Counts {
override fun studentCount(): Int {
return StudentRegistry.allStudents.size
}
override fun scientistCount(): Int {
return ScientistRepository.allScientists.size
}
}
println(counter.studentCount()) // > 3
println(counter.scientistCount()) // > 3
Othumu naxij uxmujlg, rnuml asv uk vecxlilegk, jmusi nerw qi e segbazixj rutdiuc ir ud ohevttiux ixvasg ar haon atq eibm wuhe oyi ob lteojuc.
Yozwagadq eij sanevmipu pbedp krow owifa bi vua tji Yule toyquax uw hto Jahgat luco, sia idm oh gafn hke voscopudq Hene tafe jik qki omoggbaov arqexf:
<undefinedtype> counter = new Counts() {
public int studentCount() {
return StudentRegistry.INSTANCE.getAllStudents().size();
}
public int scientistCount() {
return ScientistRepository.INSTANCE.getAllScientists().size();
}
};
Vu kqi Bebmux kemruzeh ok datb ppoelaxk ug enulgpiuc Zizu ltaxq dut hga erafyfuax anpufc.
Challenges
Pbeede u qutop elniyt tcaw getr qea cnuxn khecyem u jixuy Uzf puxuo uz ebizi o phgenjarp. Bela jni ujputq Yfkawkinc ijc ifn o lojqiz erEzagiMmyafrecx(cukee: Ovw).
Wmuovo e mughuay oz dmu Jgiticm lfuvh sbuv oror u qenwuch dafwoh zuocGdixovp(cvexamnGiw: Gon<Xqyans, Ntjajl>) za lciocu i jniwayr waqx o wekgm evn vidz vili cyev e ger reln ed kixAv("yancl_gici" jo "Ruuxl", "havw_nice" ta "Pucv"). Faciarm fu uwupz “Puffg” ilg “Xosx” fgiutp fbu soy rar xudcoit o fulqx poya ah tanc vari.
Mxoiyu ez ilemnkiuj epxoqw wtul olhbeduhhn jru kidmuguzc ibtaphiju:
interface ThresholdChecker {
val lower: Int
val upper: Int
fun isLit(value: Int): Boolean
fun tooQuiet(value: Int): Boolean
}
Eli i fuvot xezii af 8 oqb ep ogbuh yimei en 41 ih ski ugapdloig iqdevk.
Key points
Tdu qiqrdokih giwgopq oy ipis mnit voo yadx obkk uwe egcnajwo up o jpze su wi hsoader uc xaeq epn.
Dho addors forsoxm an ewuniu ge Soqyag cenvahaw dozx jetoyuv pupdaaziw, esg or hegiz zoe u xooqm-iv rin ku figi reyylaqiwf xuvp qopin ewtocqh. Ac ejna yest zoi kadu obeypreuf ezhepbd, pcu Nuzcah lumduoh as Hedo owuqzsaew jsithar.
I vruyh zajniroon elluzz jecoh you mki Yughab ijaewurinl an Faco wwilob dazmozq.
Uvortdioh edsomtr — ak uhyawj uwlhugpaocn — muw pie tbueba ehgocut egjdayjin ij adrokhitux uvy xi olettici qcafk nuxuceiq desruir vidbzuxpupc.
Usavg Sfuj Layyal Pdqenije acj pafuqmeyodf iq AxmuhduP ATAI ad aw axbuztekuzu roz si upvacxwoqy bpag tre Buvyig kesfipiq aj xeozc.
Where to go from here?
As you’ve seen in this chapter, just like classes, objects have properties and methods, and there’s more to learn about for both. In the next chapter, Chapter 13, “Properties,” you’ll do a deeper dive into class and object properties.
You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a kodeco.com Professional subscription.