Kotlin uses object expressions and object declarations to create objects of a class that is a slight modification of some existing class, without needing to declare a new subclass.
Object Expressions
Object expressions create anonymous objects that can be used as parameters in methods:
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// ...
}
override fun mouseEntered(e: MouseEvent) {
// ...
}
})
Objects can inherit from a base class or implement other interfaces:
open class A(x: Int) {
public open val y: Int = x
}
interface B {β¦β¦}
val ab: A = object : A(1), B {
override val y = 15
}
If the supertype has a constructor, it must be passed arguments. Multiple supertypes and interfaces can be separated by commas.
With object expressions, you can obtain an object directly without defining a class:
fun main(args: Array<String>) {
val site = object {
var name: String = ""
var url: String = "www."
}
println(site.name)
println(site.url)
}
Please note that anonymous objects can only be used as types declared in local and private scopes. If you use an anonymous object as the return type of a public function or as the type of a public property, the actual type of that function or property will be the supertype of the anonymous object declaration. If no supertype is declared, it will be Any. Members added in the anonymous object will not be accessible.
class C {
// Private function, so its return type is the anonymous object type
private fun foo() = object {
val x: String = "x"
}
// Public function, so its return type is Any
fun publicFoo() = object {
val x: String = "x"
}
fun bar() {
val x1 = foo().x // OK
val x2 = publicFoo().x // Error: Unresolved reference "x"
}
}
In object expressions, you can conveniently access other variables in the scope:
fun countClicks(window: JComponent) {
var clickCount = 0
var enterCount = 0
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
clickCount++
}
override fun mouseEntered(e: MouseEvent) {
enterCount++
}
})
// β¦β¦
}
Object Declarations
Kotlin uses the object keyword to declare an object.
In Kotlin, we can conveniently obtain a singleton through an object declaration.
object DataProviderManager {
fun registerDataProvider(provider: DataProvider) {
// β¦β¦
}
val allDataProviders: Collection<DataProvider>
get() = // β¦β¦
}
To reference this object, we can simply use its name:
DataProviderManager.registerDataProvider(β¦β¦)
Of course, you can also define a variable to get this object. However, when you define two different variables to get this object, you will find that you cannot get two different variables. In other words, through this method, we obtain a singleton.
var data1 = DataProviderManager
var data2 = DataProviderManager
data1.name = "test"
print("data1 name = ${data2.name}")
Example
In the following example, both objects output the same URL address:
object Site {
var url:String = ""
val name: String = ""
}
fun main(args: Array<String>) {
var s1 = Site
var s2 = Site
s1.url = "www."
println(s1.url)
println(s2.url)
}
The output is:
www.
www.
Objects can have supertypes:
object DefaultListener : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
// β¦β¦
}
override fun mouseEntered(e: MouseEvent) {
// β¦β¦
}
}
Unlike object expressions, when an object declaration is inside another class, this object cannot be accessed via an instance of the outer class, but only via the class name. Similarly, this object cannot directly access methods and variables of the outer class.
class Site {
var name = ""
object DeskTop {
var url = "www."
fun showName(){
print{"desk legs $name"} // Error, cannot access methods and variables of the outer class
}
}
}
fun main(args: Array<String>) {
var site = Site()
site.DeskTop.url // Error, cannot access the object via an instance of the outer class
Site.DeskTop.url // Correct
}
Companion Objects
An object declaration inside a class can be marked with the companion keyword. This associates it with the outer class, allowing us to directly access the internal elements of the object via the outer class.
class MyClass {
companion object Factory {
fun create(): MyClass = MyClass()
}
}
val instance = MyClass.create() // Access internal elements of the object
We can omit the object name and use Companion instead of the declared object name:
class MyClass {
companion object {
}
}
val x = MyClass.Companion
Note: A class can only declare one internally associated object, meaning the companion keyword can only be used once.
Please note that the members of companion objects look like static members in other languages, but at runtime they are still instance members of real objects. For example, they can also implement interfaces:
interface Factory<T> {
fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass()
}
}
Semantic Differences Between Object Expressions and Object Declarations
There is an important semantic difference between object expressions and object declarations:
- Object expressions are executed immediately where they are used.
- Object declarations are lazily initialized when first accessed.
- The initialization of companion objects matches the semantics of Java static initializers, occurring when the corresponding class is loaded (resolved).
YouTip