Kotlin原始类型的函数编译

时间:2019-01-07 11:23:16

标签: function lambda kotlin jvm primitive-types

通过Kotlin编译为JVM字节码的方式的实验,我构建了以下简单脚本:

package testFunctions

import java.io.StringWriter
import java.io.PrintWriter

class ToHex : (Int) -> String {
    override fun invoke(p: Int): String {
        val e = Exception()
        val stackTrace = with(StringWriter()) {
            with(PrintWriter(this)) {
                e.printStackTrace(this)
                flush()
            }
            toString()
        }
        println(stackTrace)
        return p.toString(16).toUpperCase()
    }
}

typealias IntToStringFunction = (Int) -> String

fun main(args: Array<String>) {
    val toHex = ToHex()
    println("154 to hex: ${toHex(154)}")

    val toHexLambda: (Int) -> String = { p ->
        val e = Exception()
        val stackTrace = with(StringWriter()) {
            with(PrintWriter(this)) {
                e.printStackTrace(this)
                flush()
            }
            toString()
        }
        println(stackTrace)
        p.toString(16).toUpperCase()
    }
    println("155 to hex: ${toHexLambda(155)}")

    val toHexAlias = toHexLambda as IntToStringFunction
    println("156 to hex: ${toHexAlias(156)}")
}

看看生成的字节码,我看到testFunctions.ToHextestFunctions.TestFunctionsKt$main$toHexLambda$1类都被编译为实现kotlin.jvm.functions.Function1并定义了一个公共的

final String invoke(int p)

方法。由于此方法显然不会覆盖接口中定义的抽象方法,因此编译器会添加带有签名的合成桥

/* syntethic bridge */ Object invoke(Object p)

现在,查看主要功能中这些调用的链接方式,我注意到以下行为:

  1. toHex(154)通过调用invoke(int p)方法进行编译,因此无需任何装箱;
  2. toHexLambda(155)和toHexAlias(156)是通过调用invoke(Object p)进行编译的,因此,在实际方法调用之前,将这些参数装箱到Integer引用中。

从打印在程序输出中的堆栈跟踪中可以明显看出这种现象:

java.lang.Exception
    at testFunctions.ToHex.invoke(testFunctions.kt:8)
    at testFunctions.TestFunctionsKt.main(testFunctions.kt:25)

154 to hex: 9A
java.lang.Exception
    at testFunctions.TestFunctionsKt$main$toHexLambda$1.invoke(testFunctions.kt:28)
    at testFunctions.TestFunctionsKt$main$toHexLambda$1.invoke(testFunctions.kt)
    at testFunctions.TestFunctionsKt.main(testFunctions.kt:39)

155 to hex: 9B
java.lang.Exception
    at testFunctions.TestFunctionsKt$main$toHexLambda$1.invoke(testFunctions.kt:28)
    at testFunctions.TestFunctionsKt$main$toHexLambda$1.invoke(testFunctions.kt)
    at testFunctions.TestFunctionsKt.main(testFunctions.kt:42)

156 to hex: 9C

如您所见,testFunctions.kt:39testFunctions.kt:42都调用委托给实际方法实现的合成桥方法。

所以,现在我的问题是:考虑到在ToHex函数化的用法中,编译器可以使用使用原始类型的方法来优化调用,而函数类型(Int) -> String不能接受null作为输入,为什么Kotlin编译器无法意识到可以避免对合成桥方法的调用?

0 个答案:

没有答案