Kotlin - 扩展泛型 class 并返回子类型时出现问题

Kotlin - Problem extending a generic class and returning a subtype

我有以下情况:

abstract class K<T> {
  abstract fun bind(itemModel: T)
}
class A : K<ModelA> {
    override fun bind(itemModel: ModelA) {
        // ... do anything
    }
}

class B : K<ModelB> {
    override fun bind(itemModel: ModelB) {
        // ... do anything
    }
}
class Factory {
    companion object {
        const val TYPE_A: Int = 0
        const val TYPE_B: Int = 1

        fun create(type: Int): K {
            return when (type) {
                TYPE_A -> A()
                TYPE_B -> B()
            }
        }
    }
}

此时,我在 Factory.create 方法的 return 类型部分遇到错误,它说:"One type argument expected for class K< T >"。很明显,我正在尝试在 create 方法中 return K 的子类型,这是唯一重要的事情,而不是泛型的特定类型。

这在 Java 中是可能的。 Kotlin 的正确方法是什么?

这里有很多地方需要改进(根据评论更新)。

  • 如果参数不是TYPE_ATYPE_B
  • ,则需要添加默认值
  • 将 * 添加到参数化 K return 类型。

结果会是这样的:

fun create(type: Int): K<*> {
   return when (type) {
       TYPE_A -> A()
       TYPE_B -> B()
       else -> throw IllegalStateException("useful message")
    }
}

问题是 K 不是完整类型,就像你不能 return 一个 Java 中的 List - 你必须 return一个List<Something>。所以你需要说这将 return a K<Any> (或其他一些类型绑定)。

但是,现在您还有类型差异问题,因为 K<A> 不是 K<Any> 的子类型,除非 K 的声明是 K<out T> 但您的 bind 方法在 in 位置有 T,所以这是不可能的。这是有道理的,因为如果我给你一个调用 create 的结果,你无法知道你可以传递什么类型的东西给 bind 所以它没有那么有用。

如之前的回复所述,您可以创建 return K<*> 并且可以编译,但我不确定这会有多大用处,因为您必须知道实际类型为了调用 bind - 那就是你必须转换任何 create returns 在这种情况下你可能只构建特定类型的东西开始。

您可以通过返回 K<*> 使其编译,但您无法对返回的实例做很多事情。在 Java 中,您可以通过忽略编译器警告对原始类型执行此操作,并在开始尝试对返回的对象调用方法时简单地冒 ClassCastExceptions 的风险,但是为什么要使用泛型呢?

相反,您可以使用具体化类型,以便调用者可以传递生成的实例可以处理的类型,而不是一些数字:

    @Suppress("UNCHECKED_CAST")
    inline fun <reified T> create(): K<T> {
        return when (T::class) {
            ModelA::class -> A()
            ModelB::class -> B()
            else -> error("unsupported type")
        } as K<T>
    }