Kotlin Object Declarations and Expressions
As a matter of fact, the object keyword could be used in a number of cases in Kotlin; however, they all share the same key idea. In other words, the object keyword defines a class and creates an instance (an object) of that class at the same time. As a result, this usage can be classified in two main different topics in Kotlin programming: object declarations and expressions. This essay will provide you with some main concepts and best-practices in Kotlin Object Declarations and Expressions for Android developers.
Introduction and Overview
Basically, while working in Kotlin, often, you will deal with a keyword, called object. To be exact, this keyword has different meanings based on its context in Kotlin. Besides, as you know, static keyword is used to specify methods and properties that belong to an object in Java programming, not an instance of an object. The static keyword is also used to create singleton pattern as one of the most popular design patterns. Singleton Pattern indicates that you just define a class, which has just only one instance and supports a global point of access to it as well. In other words, singleton pattern helps you to create a single instance of an object that can be accessed and shared by other objects. In practice, Kotlin has an effective approach to address this issue. You can be able to utilize a single keyword, object, to implement the singleton pattern.
Eventually, in addition to object declarations in Kotlin, the object keyword helps you to implement anonymous classes without any boilerplate code. In short, object expressions create objects of anonymous classes. These classes are not explicitly declared with the class declaration.
Kotlin Object Declarations
Fundamentally, the singleton design pattern is helpful for objects that require to be shared among various places in your code and for resources that are expensive to create in practice. To guarantee that the class has just only one instance, you will need to determine how the object will be created. In java programming, to tackle thread-safety issues, you will need to write double checked conditions in your code as follows:
In fact, the thread-safe means that a method or class instance can be used by multiple threads at the same time without any problematic issues. So, by using double checked- locking concept, you can handle the thread-safe issues. It is known double-checked locking because there are two checks for specifying (instance == null), one without locking and another one with locking block.
However, this cannot work properly in reality. The instance also requires to be noted as volatile. The volatile keyword can be useful for making sure that multiple threads manage the singleton instance correctly.
private volatile static Singleton Instance;
Volatile keywords informs the compiler that this variable might be modified asynchronously by concurrent threads.
Obviously, this approach leads to boilerplate code. As this style of coding would be complicated for simple tasks, in most situations, Enums are used for implementing singletons in Java. Initially, the Enum instance is thread-safe. Therefore, you do not need to be concerned about double-checked locking.
In Kotlin programming, object is a particular class that just only consists of one instance. Also, Kotlin does not have static methods or fields. This means if you convert a singleton code in Java to Kotlin, all static properties and methods will be shown as companion object.
object Singleton {
private var count = 0
fun count(): Int {
return count++
}companion {
private var INSTANCE: Singleton? = null val instance: Singleton?
get() {
if (INSTANCE == null) {
synchronized(Singleton::class.java) {
if (INSTANCE == null)
INSTANCE =
Singleton()
}
}
}
return INSTANCE
}
}
}
This is called an object declaration and always has a name following the object keyword. As a matter of fact, an object declaration is not an expression. Thus, it cannot be used on the right-hand side of an assignment statement. The initialization of an object declaration is thread-safe and performed on the first time access.
In Kotlin, an object declaration inside a class can be written with the companion keyword. For instance:
class SampleClass {
companion object SampleCompanion {
fun create(): SampleClass = SampleClass()
}
}
Members of the companion object can be called easily by applying the class name as the qualifier:
val sample = SampleClass.create()
Furthermore, the name of the companion object can be removed when the companion name will be used as follows:
class SampleClass {
//… companion object {
private var count: Int = 10
fun count() {
count++
}
}
}SampleClass.Counter.count()
Moreover, it could be more powerful than Java static members, for instance, at runtime those are still instance members of real objects, it can implement interfaces. Thus, you can have an opportunity to extend classes and interfaces, and you can reference and pass it around just like other objects as well.
Finally, companion objects can implement interfaces like other objects and have extension functions and properties.
Kotlin Object Expressions
Object keyword can also be used in object expressions. When applied as an expression, object keyword helps you build anonymous objects and anonymous inner-classes. For instance, if you just require an object that does not have any insignificant super types, you can write its members in curly braces after object keyword as follows:
fun main() {
val sample = object {
val kotlin = "Kotlin"
val programming = "Programming"
override fun toString() = "$kotlin $programming"
}
print(sample)
}
In addition, to create an object of an anonymous class that inherits from other types, you should specify this type after object and a colon (:). Next, you should implement or override the members of this class as if you were inheriting from it. For example:
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { /*...*/ } override fun mouseEntered(e: MouseEvent) { /*...*/ }
})
Some Important points in Kotlin Object Expressions
- Unlike object declarations, anonymous objects are not singletons. Each time an object expression is executed, a new instance of the object is created.
- Unlike a Java anonymous inner class, it can only extend one class or implement one interface, a Kotlin anonymous object can implement multiple interfaces or no interfaces.
- In most cases, object expressions are helpful when you need to override multiple methods in your anonymous object. If you just only require to implement a single-method interface, like Runnable, you can rely on Kotlin’s support for SAM conversion.
- Just as with Java’s anonymous classes, code in an object expression can have access to the variables in the function where it was built. Nevertheless, unlike in Java, this is not limited to final variables. This means you can also modify the values of variables from within an object expression. For example:
fun countClicks(window: Window) {
var clickCount = 0 window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
clickCount++
}
})
// ...
}
In Conclusion
Essentially, the object keyword has various meanings based on its context in Kotlin, but they all share the same main idea. This means the object keyword defines a class and creates an instance (an object) of that class at the same time. As a result, this usage can be categorized in two main different topics in Kotlin programming: object declarations and expressions. This article discussed some main concepts and best-practices in Kotlin Object Declarations and Expressions, specially for Android developers based on JetBrains and Google documents and resources.