Generics 具有泛型param的Kotlin抽象类和使用类型param的方法

Generics 具有泛型param的Kotlin抽象类和使用类型param的方法,generics,kotlin,abstract-class,type-inference,Generics,Kotlin,Abstract Class,Type Inference,我试图创建一个带有泛型参数的抽象类,该类将具有子类,这些子类应该调用方法,而不必指定类型参数。 到目前为止,我有: abstract class AbstractClass<T : Any> @Autowired constructor(protected val delegate: MyService) { inline fun <T: Any> myMethod(param: Any): T? { return delegate.myMetho

我试图创建一个带有泛型参数的抽象类,该类将具有子类,这些子类应该调用方法,而不必指定类型参数。 到目前为止,我有:

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)
    }
}
我想知道是否可以自动推断类型参数?
我能重新设计我的方法吗?请注意,我需要在方法中包含
T::class.java

您不能将类的泛型参数用作具体化泛型(获取其
T::class
标记),因为在运行时泛型参数会被删除:Kotlin随后出现,并且没有类的具体化泛型。
(Kotlin仅用于内联函数)

有鉴于此,您需要传递并存储
令牌,以便使用它

此外,MyStult<代码>在您的示例中引入了一个泛型参数,它将是一个新的泛型,不以任何方式连接到类泛型参数(命名为<代码> t>代码>只增加混淆,考虑它们<代码> T1和<代码> T2< /代码>。如果我没弄错的话,你指的是类的泛型

您可以做的可能是声明一个抽象的
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)
    }
}
之后,您将能够调用
TesterWork
实例上的函数,而无需指定通用参数:

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

这里有几个问题。首先,为了从泛型类型参数检索类对象,需要对其进行具体化。为此,您需要声明


其次,声明泛型类型参数两次。一次在类声明
抽象类AbstractClass
中,一次在方法声明
中。那些
T
s是不同的。从理论上讲,您可以从方法签名中省略一个,但这不起作用,因为具体化只适用于内联方法,而不适用于类。有关该问题的可能解决方案,请参阅@hotkey的答案。

您可以将抽象类命名为a:

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}) {

}
抽象类AbstractClass(val委托:MyService,val castFn:(Any)->T){
有趣的myMethod(参数:任意):T{
返回castFn(delegate.myMethod(param))
}
}
类TesterWork(委托:MyService):抽象类(委托,{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 })
}
Inter接口{
fun myMethod(参数:任意):T
}
类NotAbstractClass(val委托:MyService,val castFn:(Any)->T):Inter{
重写方法(参数:Any):T{
返回castFn(delegate.myMethod(param))
}
}
内联fun makeClass(委托:MyService):Inter{
返回NotAbstractClass(委托,{it as T})
}
然后,您可以这样委托:

class TesterWork(delegate: MyService) : Inter<Tester> by makeClass(delegate)

val service: MyService = MyService()
val t: Tester? = TesterWork(service).myMethod("test")
class TesterWork(委托:MyService):通过makeClass(委托)进行交互
val服务:MyService=MyService()
val t:测试仪?=TesterWork(服务).myMethod(“测试”)

多亏了Fabian Zeindly,我为几个扩展类编写了一个变体。在这种情况下,它们都应该在抽象类的标题中声明

abstract class AbstractAdapter<V: AbstractAdapter.ViewHolder, I: AbstractAdapter.Item> : RecyclerView.Adapter<V>() {

    var list: List<I> = emptyList()

    override fun getItemCount(): Int = list.size

    open fun setItems(list: List<I>) {
        this.list = list.toMutableList()
    }

    open class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

    open class Item
}
抽象类AbstractAdapter:RecyclerView.Adapter(){
var list:list=emptyList()
重写getItemCount():Int=list.size
打开有趣的设置项(列表:列表){
this.list=list.toMutableList()
}
打开类ViewHolder(itemView:View):RecyclerView.ViewHolder(itemView)
公开课项目
}
然后使用新的内部类(ViewHolder、Item)扩展该类

classnewadapter(私有var监听器:View.OnClickListener?):AbstractAdapter(){
private var originalItems:List=emptyList()
覆盖有趣的设置项(列表:列表){
super.setItems(列表)
this.originalItems=list.toMutableList()
this.list=list.toMutableList()
}
覆盖创建视图持有者(视图组:视图组,i:Int):视图持有者{
val view=LayoutInflater.from(viewGroup.context)
.充气(R.layout.layout,视图组,false)
返回视图保持器(视图)
}
覆盖onBindViewHolder(viewHolder:viewHolder,i:Int){
val项目=列表[i]
viewHolder.textView.text=item.text
viewHolder.textView.tag=item.id
}
类ViewHolder(itemView:View):AbstractAdapter.ViewHolder(itemView){
val textView:textView=itemView.name
}
类项(val-id:Int,val-text:String):AbstractAdapter.Item()
}

谢谢您的回答!我有点困惑,为什么类泛型参数不能连接到方法泛型参数。当创建子类时,我们知道泛型类型,那么为什么我们不能在抽象类中使用它作为“t类型”?为什么我们必须再次指定类型?@NikolaB,当您向类及其方法添加一个泛型参数时,这些参数将是不同的,彼此没有连接,这就是我的意思。否则,您可以在函数中使用类的泛型参数。至于抽象类,JVM上的泛型以不同的方式工作:每个派生类的方法代码不会重复,因此在派生类中指定一个具体类型来代替泛型参数是没有帮助的:方法的代码仍然在基类中,然后泛型会从基类中删除。@NikolaB,也许阅读的类型擦除部分的问题将使事情更清楚。非常感谢您的帮助和解释!
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")
abstract class AbstractAdapter<V: AbstractAdapter.ViewHolder, I: AbstractAdapter.Item> : RecyclerView.Adapter<V>() {

    var list: List<I> = emptyList()

    override fun getItemCount(): Int = list.size

    open fun setItems(list: List<I>) {
        this.list = list.toMutableList()
    }

    open class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView)

    open class Item
}
class NewAdapter(private var listener: View.OnClickListener?) : AbstractAdapter<NewAdapter.ViewHolder, NewAdapter.Item>() {

    private var originalItems: List<Item> = emptyList()

    override fun setItems(list: List<Item>) {
        super.setItems(list)
        this.originalItems = list.toMutableList()
        this.list = list.toMutableList()
    }

    override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder {
        val view = LayoutInflater.from(viewGroup.context)
            .inflate(R.layout.layout, viewGroup, false)

        return ViewHolder(view)
    }

    override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
        val item = list[i]
        viewHolder.textView.text = item.text
        viewHolder.textView.tag = item.id
    }

    class ViewHolder(itemView: View) : AbstractAdapter.ViewHolder(itemView) {
        val textView: TextView = itemView.name
    }

    class Item(val id: Int, val text: String) : AbstractAdapter.Item()
}