02 - 伴生对象

伴生对象是Kotlin为弥补无静态成员而设计的特性,它允许类有一个关联的对象,可以直接通过类名访问其成员。在Java中调用伴生对象的方法需要通过.KotlinClass.Companion.的方式。Kotlin编译后,伴生对象会被转化为一个静态内部类的实例。
摘要由CSDN通过智能技术生成

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本文就来介绍 伴生对象(companion object)的知识点。


一. 伴生对象(companion object)的诞生

Kotlin 的一个特性:没有静态成员。

我们都知道,静态成员在 Java 中有很大的作用,因为 Java 没有全局变量,也不存在包级函数,一切属性和方法都是在类里面,所以在写一些工具函数和全局变量时,都需要用到 static 关键字修饰的静态成员。

Kotlin 之所以能抛弃静态成员,主要原因在于它允许包级属性和函数的存在,而且 Kotlin 为了维持与 Java 完全的兼容性,为静态成员提供了多种替代方案:

  1. 使用 包级属性和包级函数:主要用于 全局常量 和 工具函数 ;
  2. 使用 伴生对象:主要用于与类有紧密联系的变量和函数;
  3. 使用 @JvmStatic 注解:与伴生对象搭配使用,将变量和函数声明为真正的 JVM 静态成员。

二. companion 的特性

1. 声明伴生对象的语法:

companion object ObjectName : [0~N个父类型] { //伴生对象类体 }
// ObjectName 可省略

2. 特点:

  • 伴生对象相当于类的对象,可直接通过类名访问伴生对象的成员;

  • 每个类最多定义一个伴生对象;

  • kotlin 没有 static 关键字,伴生对象是为弥补 kotlin 没有 static 修饰的静态成员的不足;

  • @JvmStatic 注解只能用在伴生对象里,修饰伴生对象内的属性和函数。

三. companion 的实现

在 Kotlin 中,调用 Java 的 static 方法和调用 Kotlin 的 companion object 方法是一样的:

JavaClass.staticFun() // 调用 Java 中静态方法
KotlinClass.companionFun() // 调用 Kotlin 中伴生对象的方法

而在 Java 中,调用 static 方法和 Kotlin 中伴生 companion object 方法,有点不同:

JavaClass.staticFun(); // Java 中调用 static 方法
KotlinClass.Companion.companionFun(); // 在Java中,调用伴生companion

从 Java 的调用可以发现,companion object 的 JVM 字节码,是一个声明了一个叫 Companion 的 static 变量。 而在 Kotlin 中调用一致,其实是编译器的特殊处理结果。

来反编译一下 KotlinClass,可以看到:

// KotlinClass.class
public final class KotlinClass {
    public static final Companion companion = new Companion(null);
}

伴生对象 反编译后有如下代码:

// KotlinClass$Companion.class
public final class KotlinClass$Companion {
    private DownloadExecutor$Companion() {
    }

    public /* synthetic */ DownloadExecutor$Companion(DefaultConstructorMarker $constructor_marker) {
        this();
    }
    
    public final void companionFun() {
    }
}

可以看到,Companion 是一个叫 KotlinClass$Companion 的类的实例,带 $ 符号表示这个类是 KotlinClass 的内部类,名字叫 Companion,所以在KotlinClass中直接new Companion(null)即可。

从上面的反编译代码看,实例化 Companion 使用的是一个带 DefaultConstructorMarker 入参的构造器。

出现的场景是,若 Kotlin 编译器生成特殊构造器,就会带这个参数。上面这段代码里 Kotlin 希望能实例化 Companion 类,但又不想声明一个 public 的构造器,就声明了一个特殊的构造器。DefaultConstructorMarker 值永远为 null。

DefaultConstructorMarker 的另一个场景是:带默认参数的构造器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xl1024w

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值