Kotlin抽象类与泛型参数和使用类型参数的方法

我想创建一个抽象类与泛型参数将有子类应该调用方法, 而不必指定类型参数 。 我到目前为止:

abstract class AbstractClass<T : Any> @Autowired constructor(protected val delegate: MyService) { inline fun <T: Any> myMethod(param: Any): T? { return delegate.myMethod(param).`as`(T::class.java) } } 

并执行:

 class TesterWork @Autowired constructor(delegate: MyService) : AbstractClass<Tester>(delegate) { } 

现在当调用myMethod我必须指定类型参数:

 testerWork.myMethod<Tester>("test") 

我想知道是否有可能自动推断类型的参数? 我可以以某种方式重做myMethod吗? 请注意,我需要在方法内部有T::class.java

你不能使用类的泛型参数作为泛化泛型(得到它的T::class标记),因为在运行时泛型参数被擦除了:Kotlin遵循Java的类型擦除实践 ,没有类的泛化泛型。
(Kotlin已经将内联函数的泛型化)

鉴于此,您需要传递并存储Class<T>标记,以便可以使用它。

另外,你的例子中的myFunction引入了一个泛型参数,它将是一个新的泛型,并不以任何方式连接到类泛型参数(命名这两个T只会增加混淆,认为它们是T1T2 )。 如果我说得对,那么你的意思是这个班是“通用的”。

可能你可以做的是声明一个抽象的val ,它将存储一个类的标记并重写该函数,以便它使用存储的类标记:

 abstract class AbstractClass<T : Any> constructor(protected val delegate: MyService) { protected abstract val classToken: Class<T> fun myMethod(param: Any): T? { return delegate.myMethod(param).`as`(classToken) } } 

然后,从AbstractClass派生将需要重写classToken

 class TesterWork constructor(delegate: MyService) : AbstractClass<Tester>(delegate) { override val classToken = Tester::class.java } 

之后,您将能够在不指定通用参数的情况下调用TesterWork实例的功能:

 val service: MyService = ... val t: Tester? = TesterWork(service).myMethod("test") 

这里有几个问题。 首先,为了从泛型类型参数中检索一个类对象,你需要对其进行具体化。 为此,您需要声明<reified T: Any>

其次,你声明泛型类型参数两次。 一旦进入类声明abstract class AbstractClass<T : Any>并且一次在方法声明inline fun <T: Any> myMethod 。 那些T是不一样的。 理论上你可以省略方法签名中的一个,但是这不起作用,因为只有内联方法而不是类方法。 有关可能的解决方案,请参阅@ hotkey的答案。

你可以给这个抽象类传一个lambda:

 abstract class AbstractClass<T : Any>(val delegate: MyService, val castFn: (Any) -> T) { fun myMethod(param: Any): T? { return castFn(delegate.myMethod(param)) } } class TesterWork(delegate: MyService) : AbstractClass<Tester>(delegate, {it as Tester}) { } 

你也许也可以让这个类非抽象的,给它一个接口,让一个内联函数创建它:

 interface Inter<T> { fun myMethod(param: Any): T } class NotAbstractClass<T>(val delegate: MyService, val castFn: (Any) -> T) : Inter<T> { override fun myMethod(param: Any): T { return castFn(delegate.myMethod(param)) } } inline fun <reified T> makeClass(delegate: MyService): Inter<T> { return NotAbstractClass<T>(delegate, { it as T }) } 

那么你可以这样委托:

 class TesterWork(delegate: MyService) : Inter<Tester> by makeClass(delegate) val service: MyService = MyService() val t: Tester? = TesterWork(service).myMethod("test")