如果有時候你只是想要建立一個小型的物件,卻不想要宣告一個類別,Kotlin 允許你這樣做,這樣的寫法稱作 object expressions 和 object declarations。
說明
Object expressions
如果你要建立一個匿名類別實體,一般來說會這樣寫。
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { /*...*/ }
override fun mouseEntered(e: MouseEvent) { /*...*/ }
})
你可以同時繼承跟實作 class 以及 interface。
open class A(x: Int) {
open val y: Int = x
}
interface B
val a1: A = object : A(1), B {}
val a2: A = object : A(3), B {
override val y = 4
}
val b: B = object : A(3), B {
override val y = 4
}
fun main(args: Array<String>) {
println(a1.y) //1
println(a2.y) //2
// println(b.y) //Unresolved reference 'y'
}
你也可以單純宣告一個物件。
fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
}
這邊有幾個重點需要注意一下。
-
如果是私有的方法後面接著 object,那麼回傳就會是一個匿名物件。
-
如果是公開的方法後面接著 object,那麼回傳的就是 Any,如此一來透過這個方法存取匿名類別內的值就會無法存取。
class C {
// Private function, so the return type is the anonymous object type
private fun foo() = object {
val x: String = "x"
}
// Public function, so the return type is Any
fun publicFoo() = object {
val x: String = "x"
}
fun bar() {
val x1 = foo().x // Works
val x2 = publicFoo().x // ERROR: Unresolved reference 'x'
}
}
你也可以從外部存取變數並且改變它的值,這邊跟 Java 就不太一樣。
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 使用 Singleton,可以透過 object 關鍵字就可以達成,這邊有幾個重點要注意一下。
-
不能有建構子。
-
不能傳入參數,但是你可以透過方法來傳入。
-
不用寫 class 關鍵字。
object Person{
val userName = "givemepass"
}
- 可以實作其他介面。
interface A{
fun test()
}
object Person : A{
override fun test() {
TODO("not implemented")
}
}
反組譯來看看就會長這樣。
public final class Person {
@NotNull
private static final String userName = "givemepass";
public static final Person INSTANCE;
@NotNull
public final String getUserName() {
return userName;
}
private Person() {
INSTANCE = (Person)this;
userName = "givemepass";
}
static {
new Person();
}
}
如果要存取就可以透過這樣的方式取得。
println(Person.userName)
結果如下。
givemepass
Companion Objects
使用 Companion object 關鍵字,你可以想像成 Java 的靜態變數。
class Person{
val name = "givemepass"
companion object {
fun getInstance() = Person()
}
}
透過以下方法就可以取得該類別物件,並且拿到成員變數。
fun main(args: Array<String>) {
println(Person.getInstance().name)
}
結果如下。
givemepass
它也可以寫成以下三種狀態。
class MyClass1 {
companion object {
val num = 1
}
}
class MyClass2 {
companion object Named {
val num = 2
}
}
class MyClass3 {
companion object {
val num = 3
}
}
fun main(args: Array<String>) {
println(MyClass1.Companion.num)
println(MyClass2.num)
println(MyClass3.num)
}
結果如下。
1
2
3
object expressions、object declarations 與 companion object 的差異
-
object expressions 是立即性的,也就是說你馬上就可以得到一個物件。
-
object declarations 也就是 singleton,它是一種設計模式。
-
companion object 是 Java 的 static。
參考資料
https://kotlinlang.org/docs/reference/object-declarations.html