Kotlin学习之对象表达式与对象声明

object 的三种用法

Kotlin 的 object 关键字有三种用法:

  • 对象声明 ,一般用来实现单例
  • 伴生对象 ,类似 Java 的 static 关键字,也可以用于工厂方法模式
  • 对象表达式 ,一般用来代替 Java 的匿名内部类

对象声明

object 的语义是这样的: 定义一个类并创建一个实例 。不管是对象声明,还是下面会说到的另外两种用法,都是遵循这一语义的。

作为对象声明,它可以直接用来实现单例模式:

object Singleton{
    fun xxx(){}
}

话不多说,直接 Decompile 看 Java 代码:

public final class Singleton {
   public static final Singleton INSTANCE;

   public final void xxx() {
   }

   private Singleton() {
   }

   static {
      Singleton var0 = new Singleton();
      INSTANCE = var0;
   }
}

从 Java 代码中可以看出来,显然这是一个单例模式。

  • 私有构造函数
  • 通过静态字段对外提供实例
  • 静态代码块中直接初始化,线程安全 。

这里插播一个问题,static 代码块在何时执行?

。static 代码块就是在 初始化 阶段执行的。那么,哪些场景会触发类的初始化呢?有如下几种场景:

  • 通过 new 实例化对象
  • 读写一个类的静态字段
  • 调用一个类的静态方法
  • 对类进行反射调用

按照上面反编译出来的 Java 代码,获得单例对象的方法是 Singleton.INSTANCE ,即调用 Singleon 类的静态字段 INSTANCE,就会触发类的初始化阶段,也就触发了 static 代码块的执行,从而完成了单例对象的实例化。同时,由于类加载过程天生线程安全,所以 Kotlin 的 object 单例活脱脱的就是一个线程安全的懒汉式单例(访问时初始化)。

此外,object 声明的单例类和普通类一样,可以实现接口,继承类,也可以包含属性,方法。但是它不能由开发者手动声明构造函数,从反编译出来的 Java 代码可以看到,它只有一个 private 构造函数。

所以,这对实际的业务场景是有一定限制的。对于需要携带参数的单例类,object 就有点力不从心了。当然也不难解决,模仿 Java 的写法就行了,这里以 DCL 模式为例。

class Singleton private constructor(private val param: Int) {
    companion object {
        @Volatile
        private var instance: Singleton? = null
        fun getInstance(property: Int) =
            instance ?: synchronized(this) {
                instance ?: Singleton(property).also { instance = it }
            }
    }
}

对象表达式的格式:

object[:若干个父类型,中间用逗号隔开]{
 
}
 override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main10)
 
        val myObject = object : MyInterface {
            override fun myPrint(i: Int) {
                println("i的值是$i")
            }
        }
 
        myObject.myPrint(100)
    }

这个是对象表达式

object MyObject{
   fun method() ="hello world
}

override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
       
        MyObject.method()
    }

这个是对象声明语法。这个后面是有一个名字的,对象表达式是没有名字的。

这些对象可以有超类型:

object DefaultListener : MouseAdapter() {
    override fun mouseClicked(e: MouseEvent) { …… }

    override fun mouseEntered(e: MouseEvent) { …… }
}

对象声明和对象表达式的差别:

  • 对象表达式可以赋值给一个变量;但是对象是不可以的赋值给一个变量,对象声明本身是声明了一个对象,是不能直接放到等号右边的。
  • 对象表达式是立刻初始化的或者执行的;对象声明是延迟初始化的,在首次访问的时候进行。
  • 伴生对象是在其所对应的类被加载时初始化的,对应于Java的静态初始化。

参考资料来自https://xiaozhuanlan.com/topic/4319806527

猜你喜欢

转载自blog.csdn.net/jingerlovexiaojie/article/details/107468945