朱涛 · Kotlin 编程第一课
朱涛
Google 认证的 Kotlin、Android 开发者专家,博客“Kotlin Jetpack 实战”作者
6717 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 50 讲
朱涛 · Kotlin 编程第一课
15
15
1.0x
00:00/00:00
登录|注册

05 | object关键字:你到底有多少种用法?

你好,我是朱涛。这节课我们来学习 Kotlin 当中 object 关键字的三种语义,以及它的具体使用场景。
在前面课程中,我们学习了 Kotlin 语言的基础语法和面向对象相关的语法,其中涵盖了很多不同类型的关键字。比如说,fun 关键字代表了定义函数,class 关键字代表了定义类,这些都是一成不变的。但是今天我们要学习的 object 关键字,却有三种迥然不同的语义,分别可以定义:
匿名内部类;
单例模式;
伴生对象。
之所以会出现这样的情况,是因为 Kotlin 的设计者认为,这三种语义本质上都是在定义一个类的同时还创建了对象。在这样的情况下,与其分别定义三种不同的关键字,还不如将它们统一成 object 关键字。
那么,理解 object 关键字背后的统一语义,对我们学习这个语法是极其关键的,因为它才是这三种不同语义背后的共同点。通过这个统一语义,我们可以在这三种语义之间建立联系,形成知识体系。这样,我们在后面的学习中才不会那么容易迷失,也不会那么容易遗忘。
接下来,我们就一起来逐一探讨这三种情况吧。

object:匿名内部类

首先是 object 定义的匿名内部类。
Java 当中其实也有匿名内部类的概念,这里我们可以通过跟 Java 的对比,来具体理解下 Kotlin 中对匿名内部类的定义。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Kotlin中的object关键字具有三种不同的语义:匿名内部类、单例模式和伴生对象。这种设计统一了类的定义和对象的创建,使得代码更加简洁和灵活。在匿名内部类的使用中,Kotlin通过object关键字来创建接口和抽象类的实例,同时支持继承抽象类和实现多个接口,相比Java更加灵活。而在单例模式中,使用object关键字可以轻松创建单例类,省去了在Java中繁琐的实现过程。虽然这种方式存在一些局限性,如不支持懒加载和传参构造单例,但Kotlin也提供了其他方式来实现单例模式,如伴生对象。通过object关键字的三种用法,读者可以深入了解Kotlin语法的灵活性和简洁性,以及与Java的对比优势。伴生对象的实战应用包括工厂模式,通过伴生对象巧妙地实现了工厂模式,统一管理类的创建,同时可以进行统一的判断,如敏感词过滤和判断用户的名称是否合法。通过伴生对象,还可以实现更加复杂的单例设计模式。文章还介绍了Kotlin中更加全面的四种单例模式,包括懒加载委托单例模式、Double Check单例模式、抽象类模板单例和接口单例模板。这些模式的介绍和比较为读者提供了更多选择和灵活性,使得他们能够根据具体需求选择最适合的单例模式。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《朱涛 · Kotlin 编程第一课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(22)

  • 最新
  • 精选
  • InfoQ_0880b52232bf
    ”由于static{}代码块当中的代码,是在类加载的时候被执行的...“ 这句话是有问题的,静态代码块不是在类加载的时候执行的,而是在类初始化时执行的。

    作者回复: 很抱歉出现了这个疏漏,我会改过来。也真心感谢你指出了这个问题,你让这个课程变得更好了。

    2022-01-08
    2
    21
  • 7Promise
    BaseSingleton有一个缺点:限制了单例的构造函数只有一个参数。因此可以将p改为函数类型传入。

    作者回复: 不错的思路~

    2022-01-05
    5
    8
  • 阿康
    我感觉可以把P换成高级函数当做参数传入,未必每个单例的creator 内部方法都是一样的,是吧?

    作者回复: 不错的思路~

    2022-01-05
    7
  • A Lonely Cat
    class DatabaseManager private constructor() { companion object { @JvmStatic val instance by lazy { DatabaseManager() } } } 这样写也行

    作者回复: 赞~

    2022-01-07
    6
  • 白乾涛
    1、文章中说"Kotlin 还是为我们提供了伴生对象,来帮助实现静态方法和变量" --- 请问伴生对象(companion object)和静态有关系吗?我感觉只是 @JvmStatic 和静态有关系。 2、文章中说"伴生对象,是嵌套单例的一种特殊情况" --- 请问伴生对象还能叫单例吗?反编译后,他都有 public 的构造方法了,而且 static 代码块也不见了 3、文章中说"@JvmStatic修饰的方法或属性会被挪到伴生对象外部的类当中" --- 这里不应该称为【挪到】吧,因为内部类中的 foo 方法还在那里,说【拷贝】更合适 4、请问【伴生对象 + @JvmStatic】有什么意义?单纯拷贝一个成员到外部类中并没有什么意义吧?

    作者回复: 首先,感谢这位同学能提出这么多有趣的见解,这里我一一回复: 第一点:站在Kotlin语法层面,“伴生对象”跟“静态”已经是语法等价了。 第二点:这也是语法层面上的推导,只是说它们语法发展上的关系。另外,伴生对象确实是单例,只是我们一般不这么用。(我提供的反编译代码中public的构造方法只有编译器才能访问,我们开发者是无法直接调用的。) 第三点:确实说【拷贝】更合适。 第四点:【伴生对象 + @JvmStatic】,它的意义在于让Java调用Kotlin的时候更友好。

    2022-02-10
    3
    5
  • louc
    BaseSingleton 的提取之前,getInstance 在子类的companion object中可以加 @JvmStatic,但是提取后就无法加这个注解了,造成java代码调用不友好了,这个算个缺点吧

    作者回复: 是的。

    2022-04-14
    2
  • 白乾涛
    使用 object 定义匿名内部类的时候,可以在继承一个抽象类的同时,来实现多个接口,但是反编译后为啥语法不正确? public static final void main() { <undefinedtype> item = new A() { public void funA() { } public void funB() { } public void findMan() { } }; item.findMan(); }

    作者回复: 字节码反编译成Java其实也是有损的。

    2022-02-09
    2
  • 郑峰
    creator 是唯一一个需要实现的方法,我们可以使用 SAM 转换,最终使用 Lambda 表达式来简化它的写法。 open class BaseSingleton<in P, out T : Any>(private val creator: (P) -> T) { @Volatile private var instance: T? = null fun getInstance(param: P): T = instance ?: synchronized(this) { instance ?: creator(param).also { instance = it } } }

    作者回复: 嗯,不错的思路。

    2022-01-16
    2
  • 神佑小鹿
    companion 只是为了将 @jvmstatic 修饰的方法,挪到外面么??

    作者回复: 由于companion无法单独使用,如果要对比“companion object”与“object”,那么它们之间的差异,就在于字节码上的这些变化了。

    2022-04-04
    1
  • 木易杨
    class Utils{ @JvmStatic fun foo(){ println("foo") } } 为啥@JvmStatic不能再class中写了?只能在object中。

    作者回复: 因为@JvmStatic是用来修饰静态成员的啊,你想想是不是?

    2022-01-13
    3
    1
收起评论
显示
设置
留言
22
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部