Biểu thức và khai báo đối tượng — Object expressions and declarations
Đôi lúc chúng ta cần tạo một đối tượng với sự thay đổi nhỏ với lớp, và không có lớp con từ nó. Kotlin giới thiệu 2 đối tượng là biểu thức và khai báo.
Biểu thức đối tượng — Object expressions
Biểu thức đối tượng tạo ra các đối tượng của lớp vô danh tức là lớp không có chỉ rõ với từ khoá class
khi khai báo. Ví dụ lớp được dùng cho một lần dùng. Bạn có thể định nghĩa biểu thức đối tượng từ ban đầu, kế thừa từ lớp có sẵn, hoặc hiện thực các giao diện. Các thí dụ của lớp vô danh cũng được gọi là đối tượng vô danh bởi vì chúng được định nghĩa bởi biểu thức không phải có tên.
Đối tượng vô danh được tạo từ ban đầu với từ khoá object
Nếu chúng ta chỉ cần đối tượng không cần kế thừa từ một kiểu nào đó thì chỉ cần khai báo các thuộc tính, hoặc hàm trong nó
val helloObject = object {
val hello = "Hello"
val object1 = "Object"
override fun toString(): String {
return "$hello $object1"
}
}
fun main() {
println(helloObject)
}
Đối tượng vô danh được tạo từ kế thừa từ kiểu cha
Để tạo kế thừa từ kiểu cha chúng ta có từ khóa object và theo sau là tên của cha
interface MouseEvent
abstract class MouseAdapter {
abstract fun mouseClicked(e: MouseEvent)
abstract fun mouseEntered(e: MouseEvent)
}
val mouseAdapter = object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {}
override fun mouseEntered(e: MouseEvent) {}
}
Nếu kiểu cha có hàm khởi tạo thì đối tượng cần phải khởi tạo khi kế thừa và đối tượng có thể kế thừa và hiện thực interface
val mouseAdapter: MouseAdapter = object : MouseAdapter(), MouseEvent {
override fun mouseClicked(e: MouseEvent) {}
override fun mouseEntered(e: MouseEvent) {}
}
Đối tượng vô danh được dùng như kiểu trả về
Khi một đối tượng vô danh được dùng là thuộc tính hoặc hàm riêng (không phải là hàm inline
) của class thì các hàm trong lớp có thể truy xuất thuộc tính hoặc hàm của đối tượng vô danh.
class Student {
private fun getObject() = object {
val x: String = "x"
}
fun printX() {
println(getObject())
}
}
Nếu đối tượng vô danh là public
hoặc là private inline
, thật sự nó là:
Any
nếu đối tượng vô danh không có kế thừa từ một kiểu cha nào- Nếu được khai báo kế thừa từ một kiểu cha, thì nó có kiểu giống kiểu cha
- Nó sẽ tường minh nếu có nhiều hơn kiểu cha
Trong tất cả các trường hợp này của đối tượng vô danh là không thể truy xuất được. Các thành viên được override
có thể truy xuất được nếu chúng được khai bao kiểu thật sự của hàm hoặc thuộc tính.
class C {
// The return type is Any. x is not accessible
fun getObject() = object {
val x: String = "x"
}
// The return type is A; x is not accessible
fun getObjectA() = object: A {
override fun funFromA() {}
val x: String = "x"
}
// The return type is B; funFromA() and x are not accessible
fun getObjectB(): B = object: A, B { // explicit return type is required
override fun funFromA() {}
val x: String = "x"
}
}
(tham khảo từ https://kotlinlang.org/docs/object-declarations.html#using-anonymous-objects-as-return-and-value-types)
Truy xuất biến bên trong đối tượng vô danh
Đối tượng biểu thức có thể truy xuất đến code trong phạm vi cho phép
class Window {
fun addClick(adapter: MouseAdapter) {}
}
fun countClicks() {
var clickCount = 0
var enterCount = 0
val window = Window()
window.addClick(object: MouseAdapter() {
override fun mouseClicked(e: MouseEvent) {
clickCount++
}
override fun mouseEntered(e: MouseEvent) {
enterCount++
}
})
}
Khai báo đối tượng
Việc dùng mẫu Singleton
rất hiệu dụng trong rất nhiều ngữ cảnh và Kotlin dùng object
để khai báo là duy nhất.
object StudentManager {
private val students = mutableListOf<Student>() val allStudents get() = students fun registerStudent(student: Student) {
students.add(student)
}
}
Nó được gọi là khai báo đối tượng và thường có từ khóa object
. Giống như khai báo một biến, một đối tượng khai báo không phải là một biểu thức, và nó không không được dùng như việc gán giá trị.
Sự khởi tạo của một khai báo đối tượng là luồn an toàn và hoàn thành trong gọi lần tiên.
Để tham chiếu đến đối tượng thì gọi tên trực tiếp
val allStudents = StudentManager.allStudents
Đối tượng khai báo không thể được khai báo bên trong hàm hoặc lớp bên trong. Nó có thể được khai báo bên trong một khai báo đối tượng khác.
Đối tượng đồng hành — Companion Object
Một đối tượng được khai báo trong một lớp và được đánh dấu với từ khoá companion
class Configuration {
companion object Constants {
const val DELAY_TIME_MILLISECONDS = 1000L
}
}
Thành viên của đối tượng đồng hành có thể truy xuất theo tên lớp
val delayTime = Configuration.DELAY_TIME_MILLISECONDS
Tên của đối tượng đồng hành có thể được lượt bỏ và trong trường hợp này khi dùng chúng ta cần phải có từ khoá companion
.
class Config {
companion object {
const val HTTP_OK = "OK"
}
}
val httpOk = Config.Companion.HTTP_OK
Các thành viên của lớp có thể truy xuất các thành phần private
của đối tượng đồng hành.
Tên của một lớp được sử dụng bởi chính nó (không phải là định nghĩa cho một tên khác) hoạt động như một tham chiếu đến đối tượng đồng hành của lớp (cho dù có tên hay không):
class MyClass1 {
companion object Named {}
}
val x = MyClass1
class MyClass2 {
companion object {}
}
val y = MyClass2
Lưu ý rằng mặc dù các thành viên của các đối tượng đồng hành trông giống như các thành viên tĩnh trong các ngôn ngữ khác, trong thời gian chạy, chúng vẫn là các thành viên thể hiện của các đối tượng thực và có thể, chẳng hạn, có thể triển khai các giao diện:
interface Factory<T> {
fun create(): T
}
class MyClass {
companion object : Factory<MyClass> {
override fun create(): MyClass = MyClass()
}
}
val f: Factory<MyClass> = MyClass
Tuy nhiên, trên JVM
, bạn có thể có các thành viên của các đối tượng đồng hành được tạo dưới dạng các trường và phương thức tĩnh thực sự nếu bạn sử dụng chú thích @JvmStatic
. Xem phần khả năng tương tác Java để biết thêm chi tiết.
Sự khác biết ngữ nghĩa của biểu thức và khai báo đối tượng
- Biểu thức đối tượng được thực thì và khởi tạo tại thời điểm được dùng
- Khai báo đối tượng chỉ được khởi tạo cho lần đầu dùng.
- Đối tượng đồng hành được khởi tạo khi lớp tương ứng của nó được tải.
Cảm ơn các bạn đã đọc bài. Đăng ký kênh chúng tôi để xem những bài học mới nhất.
Youtube kênh: https://bit.ly/2EFOOXs
Thảo luận bằng cách comment ở đây hoặc trong video của blog này.