美文网首页
Kotlin 类扩展实现原理

Kotlin 类扩展实现原理

作者: markRao | 来源:发表于2021-07-19 10:34 被阅读0次

在 Kotlin 中当项目集成第三方 SDK 的时候,如果需要为其中某个类新增方法来可以通过 className.methodName(){}, 即 类名.方法名 的形式来扩展函数,那么同样和 Java 一样是 JVM 语言的 Kt 为什么就可以实现这种功能呢,以下为一个例子,借助它来详细探讨一下实现原理及细节。

open class Father {
    //定义成员函数
    open fun shout() = println("Father call shout()")
}
class Son : Father() {
    //子类重写父类成员函数
    override fun shout() {
        println("Son call shout()")
    }
}
// 定义子类和父类扩展函数
fun Father.eat() = println("Father call eat()")
fun Son.eat() = println("Son call eat()")

fun main() {
    val obj: Father = Son()
    obj.shout()
    obj.eat()
}

// 执行结果
Son call shout()
Father call eat()

在 IDEA 中,打开 Kt 字节码预览如下

public final class test/Son extends test/Father {
// 省略 Son 字节码细节
}

public class test/Father {
// 省略 Father 字节码细节
}

public final class test/Test16Kt {

  // Father 的类扩展实际实现
  public final static eat(Ltest/Father;)V
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
   L0
    ALOAD 0
    LDC "$this$eat"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
   L1
    LINENUMBER 16 L1
    LDC "Father call eat()"
    ASTORE 1
   L2
    ICONST_0
    ISTORE 2
   L3
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
   L4
   L5
    LINENUMBER 16 L5
    RETURN
   L6
    LOCALVARIABLE $this$eat Ltest/Father; L0 L6 0
    MAXSTACK = 2
    MAXLOCALS = 3

  // // Son 的类扩展实际实现
  public final static eat(Ltest/Son;)V
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
    @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
   L0
    ALOAD 0
    LDC "$this$eat"
    INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
   L1
    LINENUMBER 18 L1
    LDC "Son call eat()"
    ASTORE 1
   L2
    ICONST_0
    ISTORE 2
   L3
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    ALOAD 1
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/Object;)V
   L4
   L5
    LINENUMBER 18 L5
    RETURN
   L6
    LOCALVARIABLE $this$eat Ltest/Son; L0 L6 0
    MAXSTACK = 2
    MAXLOCALS = 3

  // access flags 0x19
  public final static main()V
   L0
    LINENUMBER 21 L0
// 实例化 Son
    NEW test/Son
    DUP
// 调用 Son 类的 init 方法
    INVOKESPECIAL test/Son.<init> ()V
// 检查转换为 Father 类型
    CHECKCAST test/Father
    ASTORE 0
   L1
    LINENUMBER 22 L1
    ALOAD 0
// 调用 Father.shot() ,但是因为实例为 Son ,所以执行的还是 Son 重写的 shot()
    INVOKEVIRTUAL test/Father.shout ()V
   L2
    LINENUMBER 23 L2
    ALOAD 0
<-- 问题 1 -->
    INVOKESTATIC test/Test16Kt.eat (Ltest/Father;)V
   L3
    LINENUMBER 24 L3
    RETURN
   L4
    LOCALVARIABLE obj Ltest/Father; L1 L4 0
    MAXSTACK = 2
    MAXLOCALS = 1

  // access flags 0x1009
  public static synthetic main([Ljava/lang/String;)V
    INVOKESTATIC test/Test16Kt.main ()V
    RETURN
    // 省略部分无关的实现
  // compiled from: test16.kt
}
����
�test�Test16Kt"*

上述代码示例的 kt 文件名为 Test16,在问题 1 ,我们类中的代码 obj.eat() 在字节码中实际上是调用了 Test16Kt.eat(Ltest/Father;)V ,那么根据这个规律可以得知,类扩展实际上生成了一个当前文件名+Kt 的 class,然后把已扩展的实例作为参数传递进去,具体我们可以查看 Test16Kt 类中 public final static eat(Ltest/Son;)V 和 public final static eat(Ltest/Father;)V,那么最后一个疑问,为什么 obj 是 Son 的实例却调用了父类的扩展函数,子类调用父类扩展函数的原因,根据类扩展的字节码实现可以得知这不是因为继承,实际原因是在申明时把类型设置为 Father,如果将代码改为 val obj = Son(),那么字节码中就是调用 INVOKESTATIC test/Test16Kt.eat (Ltest/Son;)V

相关文章

  • Kotlin 扩展函数实现原理分析

    Kotlin 扩展函数实现原理分析 Kotlin 的扩展函数非常的方便好用,支持给现有的java类增加函数,代码如...

  • kotlin 扩展属性

    与扩展方法类似,扩展属性当然也不是真正添加进了原类。 扒开糖衣看看kotlin扩展属性实现原理。 给Date类添加...

  • Kotlin 类扩展实现原理

    在 Kotlin 中当项目集成第三方 SDK 的时候,如果需要为其中某个类新增方法来可以通过 className....

  • Kotlin的扩展属性和扩展方法

    扩展方法的原理 Kotlin 中类的扩展方法并不是在原类的内部进行拓展,通过反编译为Java代码,可以发现,其原理...

  • 探究 Kotlin 类代理

    Kotlin 实现类代理是通过 by 关键字,本文尝试讲解类代理在 Kotlin 的具体使用和实现原理。 首先,在...

  • iOS-底层原理17:类扩展 与 关联对象 底层原理探索

    本文的主要目的是针对类的加载的一个扩展,主要讲讲类扩展和分类的底层实现原理 1. 类扩展底层原理探索 1.1 类扩...

  • Kotlin 小知识

    扩展函数(据我所知,kotlin扩展函数不是存放在被扩展的类里面的,它的实现机制是使用装饰器模式实现的)is 和 ...

  • kotlin语言学习10 ——kotlin 可见性与扩展

    本节主要介绍kotlin的可见性与kotlin中的扩展功能的使用,包括:扩展类、扩展方法、扩展伴生对象、扩展属性等...

  • Kotlin函数关键字inline内联函数原理

    前言 Kotlin扩展函数为我们提供了方便的开发调用,不用通过继承或者装饰者模式来实现功能的扩展,它的内部原理其实...

  • [iOS] 类扩展和关联对象

    本文主要是针对类的加载的扩展,探索下分类的底层实现原理。 1. 类扩展和分类介绍 1.1 category 类别、...

网友评论

      本文标题:Kotlin 类扩展实现原理

      本文链接:https://www.haomeiwen.com/subject/zoscmltx.html