The one and only object

Kotlin Vocabulary

Android Developers
Published in
5 min readMay 1, 2020

--

In Java, the static keyword is used to denote methods and properties that belong to an object, not to an instance of an object. The static keyword is also used to create Singletons, one of the most widely used design patterns. Singletons help you to create a single instance of an object, which can be accessed and shared by other objects.

Kotlin has a more elegant way to deal with this. You can use a single keyword: object, to implement the Singleton pattern. Read on to find out the differences between implementing a Singleton in Java vs Kotlin, how you can create Singletons in Kotlin without using the static keyword (spoiler this is achieved by using the object keyword), and to find out what’s happening under the hood when you’re using object.

First, let’s back up a bit and find out why we need a single instance of an object, aka Singleton.

What is a Singleton?

Singleton is a design pattern which ensures that a class has only one instance and provides a global point of access to the object. The Singleton pattern is particularly useful for objects which need to be shared between different parts in your app and for resources that are expensive to create.

Singleton in Java

To guarantee that a class has only one instance, you need to control how the object is created. To create a class with only one instance, make the constructor private and create a publicly accessible static reference of the object. While doing this, you don’t really want to create the Singleton at startup since Singletons are used for objects which are expensive to create. To achieve this, provide a static method which checks if the object is created. The method must return the previously created instance or call the constructor and return the instance.

The above code seems fine, but there is a major issue. This code is not thread-safe. At any time one thread can pass this if check but be put on hold while another thread creates the singleton. When the first thread resumes inside the if block, it creates another instance.

To fix the threading issue, you can use double checked locking. With double checked locking, if the instance is null, synchronized keyword creates a lock and a second check ensures the instance is still null. If the instance is null, then creates the Singleton. Yet, this is not enough and the instance also needs to be marked volatile. Volatile keyword tells the compiler that a variable might be modified asynchronously by concurrently running threads.

All of this leads to a lot of boilerplate that you need to repeat each time you need a singleton. Since this code is too complicated for such a simple task, enums are used for creating singletons in Java most of the time.

Singleton in Kotlin

Now, let’s take a look at Kotlin. Kotlin doesn’t have static methods or fields so how can we create a Singleton in Kotlin?

Actually, Android Studio/IntelliJ can help us to understand. When you convert the Singleton code in Java to Kotlin, all static properties and methods are moved to a companion object.

The converted code works as expected but we can make it simpler. To simplify the code, remove the constructor and companion keyword from object. The differences between object and companion objects are covered later in this post.

When you want to use the count() method, you can access it over the Singleton object. In Kotlin, object is a special class that only has one instance. If you create a class with the object keyword instead of class, the Kotlin compiler makes the constructor private, creates a static reference for the object, and initializes the reference in a static block.

Static blocks are called only once when the static field is first accessed. The JVM handles the static blocks in a similar way to synchronized blocks, even though they don’t have the synchronized keyword. When this Singleton class is initializing, the JVM acquires a lock on the synchronized block, making it impossible for another thread to access it. When the lock is released, the Singleton instance is already created so the static block won’t execute again. This guarantees that there is only one instance of the Singleton, which fulfills the Singleton contract. Plus, the object is both thread-safe and lazily created the first time it is accessed. Voila!

Let’s take a look at decompiled Kotlin byte code to understand what’s happening under the hood.

To check the byte code of a Kotlin class, select Tools > Kotlin > Show Kotlin Bytecode. Once Kotlin byte code is displayed, click Decompile to reveal the decompiled Java code.

However, object comes with a limitation. object declarations can not have constructors which means they can not take parameters. Even if they did, it would be impossible to pass a parameter since the non-static parameter passed in the constructor isn’t accessible from the static block.

⚠️The static initialization blocks, just like other static methods, can only access static properties of a class. Static blocks are called before the constructors so there is no way they can access properties of an object or parameters passed in the constructor.

companion object

companion object is similar to object. companion object is always declared in a class and their properties can be accessed by using the host object. The companion object doesn’t require a name. If the companion object has a name, the caller can access the members using the companion object’s name.

For example, here we have the similar companion objects with and without a name. Any caller can access the count() method on SomeClass, just like it is a static member of SomeClass. Alternatively any caller can access the count() method by using Counter just like a static member of AnotherClass.

The companion object decompiles into an inner class with a private constructor. The host class initializes the inner class through a synthetic constructor, which only it can access. The host class keeps a public reference to the companion object which is accessible from other classes.

Object Expressions

So far we’ve seen the object keyword used in object declarations. object keyword can be used in object expressions as well. When used as an expression, object keyword helps you to create anonymous objects and anonymous inner classes.

Let’s say you need a temporary object to hold some values. You can declare and initialize your object with the desired values on the spot and access them later.

In the generated code, this translates into an anonymous Java class, marked by <undefinedtype>, to store the anonymous object with generated getters and setters.

The object keyword also helps you to create anonymous classes without writing any boilerplate code. You can use an object expression and the Kotlin compiler generates the wrapper class declaration to create an anonymous class.

The object keyword helps you create thread-safe singletons, anonymous objects and anonymous classes with less code. With object and companion object, Kotlin generates all the code to achieve the same functionality offered by static keyword. Plus, you can use object expressions to create anonymous objects and classes without any boilerplate code.

--

--