美文网首页
Kotlin当中如何实现泛型类型的(假)不擦除

Kotlin当中如何实现泛型类型的(假)不擦除

作者: Wannay | 来源:发表于2022-05-19 01:23 被阅读0次

    在Spring Boot源码当中,为我们提供了下面两个扩展函数。

    inline fun <reified T : Any> runApplication(vararg args: String): ConfigurableApplicationContext =
            SpringApplication.run(T::class.java, *args)
    
    inline fun <reified T : Any> runApplication(vararg args: String, init: SpringApplication.() -> Unit): ConfigurableApplicationContext =
            SpringApplication(T::class.java).apply(init).run(*args)
    

    我们原本想要去启动SpringBoot应用,我们应该写的代码如下:

    SpringApplication.run(App::class.java,*args)
    

    但是在SpringBoot当中,因为它为我们提供了扩展函数,我们完全可以使用如下的方式去启动一个SpringBoot应用。

    runApplication<App>(*args)
    

    不仅如此,SpringBoot还为我们提供了另外一个重载的runAppplication的扩展函数,支持去提供一个init函数对SpringBoot的SpringApplication去进行初始化,接着再完成启动。

        runApplication<App>(*args) {
            // do something...
        }
    

    在执行SpringApplication.run之前,会先执行提供的init函数,再去执行run方法,实现对SpringApplication的提前初始化。

    这个扩展函数等价于下面的操作(虽然说也许作为一个CRUD程序员,你并不会用到这么进行操作)。

        val springApplication = SpringApplication(App::class.java)
        // do something
        springApplication.run(*args)
    

    好了,回到原来的问题上来。我们发现,居然可以使用T::class.java去获取泛型的类型?我们知道,java当中,可不能对泛型T去进行任何的操作啊(你会发现IDEA居然不会给你任何的提示),这里的T,居然能获取到Java类型(Class)?真的神奇!

    其实你想让方法知道你的泛型类型?那怎么可能,Java当中肯定是会进行类型擦除了,而且你这方法在运行时鬼知道你是啥类型!但是,你做不到的事,编译器能帮你做呀,Kotlin的编译器可比Java强大多了!首先,我们观察这个函数的特点。

    • 1.函数上加了inline关键字,说明它是一个内联函数,类似C中的内联函数,或者是宏,在编译期,直接帮你去进行代码的替换了(也就是说,运行时,这个方法都不会存在,直接给你替换到代码当中了)。
    • 2.泛型上加了reified关键字,标明我想要获取T的泛型类型。

    我们来举个例子就知道了,我们编写下面的Kotlin测试代码:

    fun main(args: Array<String>) {
        runApplication<App>(*args) {
    
        }
    }
    

    我们查看它反编译成为字节码,并转换为Java之后的代码:

       public static final void main(@NotNull String[] args) {
          Intrinsics.checkNotNullParameter(args, "args");
          String[] args$iv = (String[])Arrays.copyOf(args, args.length);
          int $i$f$runApplication = false;
          SpringApplication var3 = new SpringApplication(new Class[]{App.class});
          boolean var4 = false;
          boolean var5 = false;
          boolean var7 = false;
          Intrinsics.checkNotNullExpressionValue(var3.run((String[])Arrays.copyOf(args$iv, args$iv.length)), "SpringApplication(T::cla…a).apply(init).run(*args)");
       }
    

    我们发现,其实真的就是编译器在编译期,Kotlin编译器直接帮我们给替换了。

    如果该函数不是inline的呢?我们可以看到IDEA直接帮我们给出错误提示,reified关键字只能放在inline函数上。

    image.png

    当我们在普通的泛型参数上使用泛型T呢?IDEA也给我们报错,说不能这样使用。

    image.png

    也就是说,我们想要在Kotlin当中做到泛型类型不擦除,我们的正确姿势是:

    • 1.函数上加了inline关键字。
    • 2.泛型上加了reified关键字。

    相关文章

      网友评论

          本文标题:Kotlin当中如何实现泛型类型的(假)不擦除

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