在 Kotlin 中,由于泛型的强化,以及阻止擦除等特性的存在,使得泛型实例化成为了可能,因此我们可以写出类似于以下的函数:
fun new(): T
在 Java 中要实现这类函数无疑是困难的。那么下面来看一下 Kotlin 具体要怎么做吧,首先我们必须阻止泛型擦除:
inline fun new(): T
通过 inline 和 reifiied 可以保证泛型类型被实化,这是实例化的基础,接着就可以写以下代码:
inline fun new(): T {
val clz = T::class.java
val mCreate = clz.getDeclaredConstructor()
mCreate. isAccessible = true
return mCreate. newInstance()
}
这就是最基础的泛型实例化了,然鹅我们经常会遇到需要带参构造的情况,没有参数的构造只能满足一小部分情况,所以加个参数吧:
inline fun new(vararg params: Any): T {
val clz = T::class.java
val paramTypes = params.map { it::class.java }.toTypedArray()
val mCreate = clz.getDeclaredConstructor(*paramTypes)
mCreate. isAccessible = true
return mCreate. newInstance(* params)
}
那么有了这个函数之后,可以做些什么呢?比如说在 swing 下进行 UI 组件的实例化(其实就是想把代码写成 SwiftUI 2333):
fun button(text: String, block: JButton.() -> Unit) = new(text).also(block)
fun main(args: Array) {
button("Click") {
addActionListener { ... }
}
}
好了,下面开始炫技:
inline fun new(vararg params: Any) =
T::class.java.getDeclaredConstructor(*params.map { it::class.java }.toTypedArray()).apply { isAccessible = true }.newInstance(*params)
以上代码作用于 JVM 端,包括 Android 都可以使用,如果是 Kotlin/Native 下使用,可以这么来:
inline fun new(block: T.() -> Unit): T = memScoped { alloc().also(block) }
于是我们可以在 macos 的 target 下,写这样的代码:
val sz = new {
width = 0.0
height = 0.0
}
这样就初始化了一个 CGSize 对象。