在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
函数上。
当我们在普通的泛型参数上使用泛型T呢?IDEA也给我们报错,说不能这样使用。
image.png也就是说,我们想要在Kotlin当中做到泛型类型不擦除,我们的正确姿势是:
- 1.函数上加了
inline
关键字。 - 2.泛型上加了
reified
关键字。
网友评论