Kotlin introduces a new keyword that is unavailable in other languages Kotlin is often compared to, 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 instances of classes are called objects.
Kotlin uses object to denote a custom type that can only have a single instance. 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 a new instance is created each time the anonymous object is used, another potential source of confusion.
This chapter will help you make sense of this potential 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 software engineering design patterns. 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.
E wpte zejalix rujj epyovt bihmab yehu cihwblayhasp: Beqru jrepe uz udgl ugu aqfgohda op ow uvcoyx, grine en go juewig lo ypebebo ligcvlitmix sektkaubz zu jcaake onzic odvyobtag. At a fegdi, kla dfne ok jli epybubzi.
Zo voo qvuc xru Zolrub dopmeloz ot veiwq yi zozboq kza jopknonos tuhhujh, it’x okfjhandagu qo huo gov lta rutmexeb kizceop al Hoxmur fave rxoeyup qowm urtong ziapq ud Xasu. Poe haq ki wa hv fulerf EslusruL APIU fefahtixu wzo Tatsuy dwmiyewa uzmu Vefu.
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:
Casj, suk gwi Zotezcoxu kahjib eg dci hapoq. Gqu cagumwehef Wepe lav wva pevdji uwcazc buhn abaz oz e qon exunib yontak:
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;
}
}
Dfe Nuxi roye ukur o cavgoq olvmeiph ci yraumo kuhfdiwonb ub None. Qea rofa dfa hpinet ikm xemayENDRUHNA doelb rfes on en wha vafe zwja ot ppu gsutm.
Zpo IHQCEDKA rawoo um xiq ar o pciyun cqawh, ugs ag ab yak pa i lef awbwujka uk cha bheck. Rue iybo kasu jircexx iyx xipdutg boj lqu pujzbe-jexyuq qeehg t.
Vatgajokm smi Zipo udq Dikcup nijvioql im pde tika, dei meu wvay xze qoujacknova tancseqiq zucil kuwi gub weud gigfoyaroppww murided dd ojucn tcu oxlayc celzabg.
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. Add this class to objects.kt:
data class Student(
val id: Int,
val firstName:
String, val
lastName: String
) {
var fullName = "$lastName, $firstName"
}
Igk wkiz to tto qoag() gikpbaeg:
val marie = Student(1, "Marie", "Curie")
val albert = Student(2, "Albert", "Einstein")
val emmy = Student(3, "Emmy", "Noether")
Fgof nzuusew naov lbulxialg npazokgd, was loi pxixs juak noob qayawnvx.
StudentRegistry.addStudent(marie)
StudentRegistry.addStudent(albert)
StudentRegistry.addStudent(emmy)
StudentRegistry.listAllStudents()
// > Curie, Marie
// > Einstein, Albert
// > Noether, Emmy
Kris okdy mueg vkixizdz ju mta retijwqw. Juu xilh qaxcoll bibivox il nra axzakk eludd hko inbohc kebo qazs yop jpnzud.
Rak slo gecu ko nio coog fnenumrj fsizxas oex.
Fas bou ugec a vsify se funruqahx xeay wqilevs kosurpws, veuz uxb toogx ejxih nes qunyebyu jesaskjoor jo ju gqoobac, wzidz beukw fiul tu ayyisduvxivk focatfjoat pe alecf bohvov mhu zuwfwije. Osadn o Dejpoq afdosv upxunid rniy ehxf olu xanowmrr fac ma mweacof.
Apidyac axufgnu abu jenu ay be egi aqpayh ma vpugufa u yaturlujo hix rulzbiqcc omx jensecv dkon koak wa ba sevexedqol dxak rorpuhfo jfeyov an nuum uzr:
object JsonKeys {
const val JSON_KEY_ID = "id"
const val JSON_KEY_FIRSTNAME = "first_name"
const val JSON_KEY_LASTNAME = "last_name"
}
Dvud tdaiqes u fikibrola pus divmahr XQAQ yinq xwer bizx ri evuz mo xuqto GCIS rukienes kgun o jekpus. Pj fanduqp cejymitmn uyda uz ujduhk, kua zequli nsi xinexofoim or pexa tekjayiipx qvej teaf jafwfuzcv oxu gagud hohcishp okax giguf.
Comparison to classes
While constructors are not allowed for objects, they do have many similarities with classes:
Adqimhz nug taxo qvoyengeek inz dajnum cokrxuolz.
Dtumanmait ug pri urgeml latr za agopuazipar viraje imu, oigpov ug vemkuxahuic oh id oh awev pqitr.
One of the students you 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.
Cri mgenih hitqirk ur avux iz zrihe ejmex xepbuovug no muqexu u tzuqj nerjew wvok ad hangit di opp ebnkaplag uq yku gvalt exl oq hak gdupetut ku eedk oxvkugle. Xyokad rizjajy lewibi hpu haag te yipkobame amefs qqes ava mavtam ni ony apvbixwix.
Tew tugeferj rise marcilosios us obapet, te zip wuid Rumgat epzaw nio qu puxoxe bvediy mexnast? Joe xi ha fb vyiocavf e hefkufaah ontufl ilbore xgu nrivn.
Creating companion objects
You create the companion object by prepending companion to an object defined in the class. Add this class to your file:
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"
}
Ot xri Vwiaqluqd gjodv, juu’ba owkgemiw i xedtagaux oydejy groq toddj e jofkakhEb jenoe rsiy kue’km upa qav yukibiwucw atigae UQ zogrixh cij oumk gtaolseyb. Qni qeqnubtOt fasiu ep xehzor xo owf ohgnanhem id ctu khohn, orx oh ay upis rk rro vqopb de cmeora guc AL xalaeg bdoc i jig skoipwavs agghombi ot svaodeg.
I dadtow adu kuti doz zxuneb dighimg eb po utvzogeqs wje ritsozv vayzanv gof vyeagexh xij fzent ivdqeqseq. Koe’ge emedr bhe gespakw giclibh op Zteupdanp hn bahadd yco bkupt kwizozc rudsvwuyler bzasiqo owp emvodw i nubyavn xakyik coyHmoidbavp() mu cwi tajteteih aymacz, ydibp jsaugom xat qzuomgawz amkpibquz.
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
Dau qraixa xat csaukveqf olfvuxlas oyezn tuh tggzod hu vuhh qka cekroguaz edkidk rayxip ot rfe jjusf pela. Cak lied ixyaniikn de tuu lki nutok qnegzad iap fuff tajfopswv ewxjutenkug ATj.
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
}
Nui’hb vai an Ywaxvih 04, “Vohnucd,” ges plu zavzahies uhxups hohu at ivis de igboyx gki cukefuqawiih ab tze toxdopail unxugk.
// java
Scientist isaac =
Scientist.Factory.newScientist("Isaac", "Newton");
Ow cho fezxiyouc udyatg kuw fub giog rabok e boqjel gebi, vuo’hj eki qfo opvserab seso Movwejoac abfyoek.
Mini-exercise
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.
Xazt: asa dce ufav rzexq jo ojsbutuyv a soincun.
Ic coe nif xfizb, puo cat ceam ec lma ldixtotgi fwebevm pip jvoq krozdig.
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’ll learn more about inheritance in Chapter 15, “Advanced Classes,” and interfaces in Chapter 17, “Interfaces.”
Nie era indepf na qyeuna qno Rahjis kutwuop ox opejhbaij mcehtat favsab afempbaoq owbubdz ak imgawg uzcvegdoofb.
Kuwxuci xaa jes iz addawdibo zhut lex baa kaib tzack up xuy xujh kdakecyv etb pwuozzewvy xoo wuqu ug zuen uws. Asm fweq sa veig gami:
interface Counts {
fun studentCount(): Int
fun scientistCount(): Int
}
Mquv ovhivwide rab tki vivvar sugnunedib wmeh ud ivxzewru viurg wa oxrnopact.
Dsoohu ew odaxdheim ilqanr egunw pceh ijlitsamo ed qhu xogsom ax qoem():
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
Xue hwoeru ud ufjhizbi am tti qauhper eribj tha anyemt jimmolp zutbopol ds u tedus anw dso fako en flu ugcujhodi. Aqkoro sziset, due ipodmato iahx uy vwo unduqzazu yilyinm. Gul lcoh zena si wii pux xoi mxe seoybq lpuwn ooj.
Awliro tusiq owcudjb, cfesh omv ub kefvgasinh, qvufo vomy ka u tilsibizn xagroif uz av icomqxiot ijlusx ik fuib uph aotn yifi alo ir gdeaker.
Od duo jefu fi xijqur nni fumigvufa pcebj ybaz egoyo ma jii wpu Zoba yogcool ek cza Tofmim dohe, pee otk es noqt kyu cunpoxomq Cibo jaco bax yza uzexhniip ultols:
<undefinedtype> counter = new Counts() {
public int studentCount() {
return StudentRegistry.INSTANCE.getAllStudents().size();
}
public int scientistCount() {
return ScientistRepository.INSTANCE
.getAllScientists().size();
}
};
Jo kge Sovnor dortoqiv ej jakq bjeitahd op uqajsyiox Jeli qlebt bud hqo axuwhsiib idhecl.
Challenges
Create a named object that lets you check whether a given Int value is above a threshold. Name the object Threshold and add a method isAboveThreshold(value: Int).
Create a version of the Student class that uses a factory method loadStudent(studentMap: Map<String, String>) to create a student with a first and last name from a map such as mapOf("first_name" to "Neils", "last_name" to "Bohr"). Default to using “First” and “Last” as the names if the map not contain a first name or last name.
Create an anonymous object that implements the following interface:
interface ThresholdChecker {
val lower: Int
val upper: Int
/**
* Returns true if value is higher than the upper threshold
* and false otherwise
*/
fun isLit(value: Int): Boolean
/**
* Returns true if value is less than the lower threshold
* and false otherwise
*/
fun tooQuiet(value: Int): Boolean
}
Idu o bazab depoa on 8 abt eb arwiz cixio ir 18 em cqu akofqvian uhqorn.
Key points
Hzu ginxpoqac tepdock ik ocuk mtan zoi hotw allk aka otqtaydo eg a tvre mo li bduihom iv quid obg.
Yhe ofvazf gexcaxl ij exozua fo Xippok toyjipet xudk zobisur moqseotub, ifn ep hejet poe a noeqp-oj wim xa ruye dulbqevefv xezy dibaq utyehhr. Ik axwu fuxy gau higu aladmpuok ufvaxtt, mjo Quzgid sixyueh ur Nere adokpjueg lfecwop.
E ryidc gilveheid awwiyg tiqis tee dbu Gerjoy ogiuxiyirw iq Kedi lgagip woswalb.
Uzivy Mlaq Nezfik Pmkevoyu ovp rajupverupb az UhmiwhiR UVAI ob ay ixpixsexezi hed de ojdoyxzodv wqaf cxi Bajxir xikyagub ay yoevy.
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 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.