Kotlin 中的反射和泛型
Reflection and Generics in Kotlin
我已经把自己写进了一个角落,我想要一个 Class<Foo<Bar>>
的实例。虽然没有明显的理由表明这不应该是有效的,但似乎没有办法创建一个。 Foo<Bar>::class.java
是语法错误,Kotlin没有为Class
.
提供public构造函数
我正在编写的代码是 gson 之上的抽象层。下面是一个过于简化的例子:
class Boxed<T : Any> (val value: T)
class BaseParser<U : Any> (
private val clazz: Class<U>
) {
//This works for 98% of cases
open fun parse(s: String): U {
return gson.fromJson(s, clazz)
}
//Presume that clazz is required for other omitted functions
}
//Typical subclass:
class FooParser : BaseParser<Foo>(Foo::class.java)
// Edge Case
class BarParser : BaseParser<Boxed<Bar>>(Boxed<Bar>::class.java) {
override fun parse(s: String): Boxed<Bar> {
return Boxed(gson.fromJson(s, Bar::class.java))
}
}
// not valid: "Only classes are allowed on the left hand side of a class literal"
在我的生产代码中,已经有几十个从基 class 继承的子class,并且许多重写了“解析”功能理想情况下,我想要一个解决方案不需要重构现有的 subclasses.
事实上,这是不可能的。 Class
(或 Kotlin 的 KClass
)不能保存参数化类型。他们可以容纳例如List
,但他们不能 List<String>
。要存储 Foo<Bar>
,您需要 Type (or Kotlin's KType
) and specifically ParameterizedType。这些 类 比简单的 Class
.
使用起来更复杂,也更难获得。
在 Kotlin 中获取 Type
的最简单方法是使用其 typeOf() 实用程序:
typeOf<Foo<Bar>>().javaType
Gson 同时支持 Class
和 Type
,因此您应该可以使用它。
最接近的是 Boxed::class.java
。这不是语言限制,而是 JVM 限制。 JVM 具有类型擦除功能,因此编译后不存在泛型(这也是泛型不能是基元的原因之一,因为它们需要引用类型才能表现)。
它是否适用于原始盒装类型 class?
对于这种情况,它看起来像
BaseParser<Boxed<Bar>>(Boxed::class.java as Class<Boxed<Bar>>)
可以工作(也就是说,它会在运行时进行类型检查并成功)。但这取决于“假设其他省略的函数需要 clazz”部分中究竟发生了什么。显然它不允许实际区分 Boxed<Foo>
和 Boxed<Bar>
类.
如果可能的话,我也会考虑 broot 的方法,也许通过制作 BaseParser
和新的
class TypeBaseParser<U : Any>(private val tpe: Type)
扩展一个共同的摘要class/interface。
我已经把自己写进了一个角落,我想要一个 Class<Foo<Bar>>
的实例。虽然没有明显的理由表明这不应该是有效的,但似乎没有办法创建一个。 Foo<Bar>::class.java
是语法错误,Kotlin没有为Class
.
我正在编写的代码是 gson 之上的抽象层。下面是一个过于简化的例子:
class Boxed<T : Any> (val value: T)
class BaseParser<U : Any> (
private val clazz: Class<U>
) {
//This works for 98% of cases
open fun parse(s: String): U {
return gson.fromJson(s, clazz)
}
//Presume that clazz is required for other omitted functions
}
//Typical subclass:
class FooParser : BaseParser<Foo>(Foo::class.java)
// Edge Case
class BarParser : BaseParser<Boxed<Bar>>(Boxed<Bar>::class.java) {
override fun parse(s: String): Boxed<Bar> {
return Boxed(gson.fromJson(s, Bar::class.java))
}
}
// not valid: "Only classes are allowed on the left hand side of a class literal"
在我的生产代码中,已经有几十个从基 class 继承的子class,并且许多重写了“解析”功能理想情况下,我想要一个解决方案不需要重构现有的 subclasses.
事实上,这是不可能的。 Class
(或 Kotlin 的 KClass
)不能保存参数化类型。他们可以容纳例如List
,但他们不能 List<String>
。要存储 Foo<Bar>
,您需要 Type (or Kotlin's KType
) and specifically ParameterizedType。这些 类 比简单的 Class
.
在 Kotlin 中获取 Type
的最简单方法是使用其 typeOf() 实用程序:
typeOf<Foo<Bar>>().javaType
Gson 同时支持 Class
和 Type
,因此您应该可以使用它。
最接近的是 Boxed::class.java
。这不是语言限制,而是 JVM 限制。 JVM 具有类型擦除功能,因此编译后不存在泛型(这也是泛型不能是基元的原因之一,因为它们需要引用类型才能表现)。
它是否适用于原始盒装类型 class?
对于这种情况,它看起来像
BaseParser<Boxed<Bar>>(Boxed::class.java as Class<Boxed<Bar>>)
可以工作(也就是说,它会在运行时进行类型检查并成功)。但这取决于“假设其他省略的函数需要 clazz”部分中究竟发生了什么。显然它不允许实际区分 Boxed<Foo>
和 Boxed<Bar>
类.
如果可能的话,我也会考虑 broot 的方法,也许通过制作 BaseParser
和新的
class TypeBaseParser<U : Any>(private val tpe: Type)
扩展一个共同的摘要class/interface。