2016-03-15 159 views
5

我想创建一个抽象类与泛型参数,它将有子类应调用方法而不必指定类型参数。 我有这个至今: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

回答

8

您不能使用类的泛型参数作为泛化泛型(获取其T::class令牌),因为在运行时泛型参数将被删除:Kotlin遵循Java's type erasure practice,并且没有为类指定泛型。
(科特林具有reified generics只为内联函数)

鉴于这种情况,这是由你来传递和存储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") 
+0

感谢您的回答!我有点困惑,为什么不能类泛型参数连接到方法泛型参数。当子类被创建时,我们知道泛型类型,为什么我们不能在抽象类中使用它作为“T类型”?为什么我们必须重新指定类型? – NikolaB

+0

@NikolaB,当你为**类和它的方法添加一个泛型参数时,那些将是不相互连接的不同参数,这就是我的意思。否则,你肯定可以在函数中使用该类的泛型参数。至于抽象类,JVM上的泛型以不同的方式工作:对于每个派生类,方法代码不会被复制,因此在派生类中指定具体类型代替泛型参数将无济于事:方法的代码是仍然在基类中,然后泛型将从其中删除。 – hotkey

+0

@NikolaB,可能是阅读* https://en.wikipedia.org/wiki/Generics_in_Java中的type erasure *部分会使事情更加清晰。 – hotkey

3

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

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

1

你可以给抽象类铸件拉姆达:

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")