Kotlin对象和对象表达式
在面向对象的编程世界里,万物皆对象,但是我们这里说的Kotlin
的对象(或称作对象声明),是Kotlin
语言里面的一种定义。
对象是和类一个层级的,其语法声明为
object ObjectName {}
object
修饰的对象声明,默认是单例的,也就是说,当你需要一个单例时,使用object
是最优的选择,不需要再使用其他的单例生成模式,而且它的初始化是线程安全的。
创建对象的方式和类一样
在src
的包名下面,右键->New
->Kotlin File/Class
。输入名称,并选择Object
即可。
object KotlinObj {
}
和类不同的是,对象声明是不需要和类一样创建它的对象,而且对象声明中是不能有伴生对象的,它的成员函数默认都是静态的,可以通过类.function()
的方式直接调用。
object KotlinObj {
fun eat() {
println("I am eating apple now.")
}
}
fun main() {
KotlinObj.eat()
}
刚刚我们提到了伴生对象,它是Kotlin
类中的一个对象声明,它和对象不同的是,它的使用需要借助类对象,顾名思义,创建类对象时,伴生对象也会被创建。
class KtCompObj {
companion object {
}
}
当然了,伴生对象也是可以有自己的名称的。
class KtCompObj {
companion object Com{
}
}
因为伴生对象也是直接使用类访问的,因此定义名称和不定义名称,对于使用来说没有区别。
伴生对象中的属性和函数,都是可以直接通过类调用的。
class KtCompObj {
companion object Com{
const val TAG = "KtCompObj"
fun print() {
println("This is companion object Com.")
}
}
}
fun main() {
KtCompObj.TAG
KtCompObj.print()
}
需要注意的是,伴生对象的调用和对象一样,但是它在运行时依旧是类对象的实例成员。
学完了对象和伴生对象,还有一个对象表达式。
对象表达式其实比较简单,尤其是在一些事件回调机制中,比较常用,比如
interface onClickEvent {
fun onClick()
}
val a = object : OnClickEvent {
override fun onClick() {
println("onclick event.")
}
}
另外,在匿名内部类中,也是使用对象表达式来实现的。忘记了的同学可以返回第八篇复习一下。
如果说对象是继承自某个父类的,比如:
abstract class B(type: Int) {
abstract fun b()
}
val b = object : B(1) {
override fun b() {
println("This is B with param constructor.")
}
}
当然,父类如果构造函数有参数时,我们必须传入参数,和类的继承一样。
当我们仅仅需要一个对象时,这样写也是可以的。
val c = object {
val a = 1
val b = 2
}
println(c.a + c.b)
这个称作匿名对象。
另外,对象还可以结合函数使用,让一个函数返回一个对象,而且对象表达式中也是可以定义自己的函数的。
fun obj() = object {
val a = 2
val b = 3
fun objFun() {
print("This is object fun.")
}
}
同样地,也可以实现接口或继承某个超类。
fun obj() = object: OnClickEvent {
val a = 2
val b = 3
fun objFun() {
print("This is object fun.")
}
override fun onClick() {
}
}
interface OnClickEvent {
fun onClick()
}
当函数的返回值是一个对象表达式时,对象表达式中的函数或属性,可以这样使用。
fun obj() = object: OnClickEvent {
val a = 2
val b = 3
fun objFun() {
print("This is object fun.")
}
override fun onClick() {
}
}
println(obj().a + obj().b)
obj().objFun()
最后,对象和对象表达式在运行态时,有一些区别需要注意。
-
对象表达式是在使用他们的地方立即执行(及初始化)的;
-
对象是在第一次被访问到时延迟初始化的;
-
伴生对象的初始化是在相应的类被加载(解析)时,与 Java 静态初始化器的语义相匹配。