java - Kotlin 继承与泛型

标签 java generics inheritance kotlin

我有一个抽象类,我们称之为 A。

abstract class A(private val name: String) {

    fun read(key: String): Entity {
        ...
    }

    fun write(entity: Entity) {
        ...
    }

    abstract val mapper: Mapper<Any>

    ...

    interface Mapper<T> {
        fun toEntity(entry: T): Entity

        fun fromEntity(entity: Entity): T
    }

    ...

它有一个抽象映射器。重点是我可以将不同的对象映射到实体并使用 readwrite .

我的子类,我们称之为 B,结构如下:

class B(private val name: String) : A(name) {
    override val mapper = AnimalMapper

    object AnimalMapper: Mapper<Animal> {
        override fun fromEntity(entity: Entity): Animal {
            TODO("not implemented")
        }

        override fun toEntity(animal: Animal): Entity {
            TODO("not implemented")
        }
    }
}

理想情况下,我希望在Mapper中有一个界面通用而不是 Any ,但我只是为了这个问题而简化它。

问题是我收到此错误:

Type of 'mapper' is not a subtype of the overridden property 'public abstract val mapper: Mapper<Any> defined in ...

这是为什么?

最佳答案

请注意有关继承和泛型的两个事实:

  • A val属性只能用原始属性类型的子类型覆盖。这是因为该类型的所有用户都希望它返回原始类型的某个实例。例如,可以覆盖 CharSequence属性 String .

    A var属性甚至不能使用子类型,只能使用原始类型,因为用户可能希望将原始类型的实例分配给属性。

  • Kotlin 泛型 are invariant by default 。鉴于Mapper<T> ,其任何两个实例化 Mapper<A>Mapper<B>如果 A 则不是彼此的子类型和B是不同的。

鉴于此,您无法覆盖 Mapper<Any> 类型的属性与 Mapper<SomeType> ,因为后者不是前者的子类型。

您不能使用declaration-site variance使所有Mapper<T>用法协变(将接口(interface)声明为 interface Mapper<out T> ),因为 T用作 fun toEntity(entry: T): Entity 中的参数类型.

您可以尝试申请use-site variance ,将属性声明为

abstract val mapper: Mapper<out Any>

但是这样类的用户A无法调用fun toEntity(entry: T): Entity ,因为他们不知道替换 Any 的实际类型是什么。在子类中,因此他们可以安全地通过 entry 。但是,如果用户知道确切的类型(例如 B ),他们将看到 mapper 的类型。正如它在被重写的属性中声明的那样。

<小时/>

可以让您以更灵活的方式使用重写属性的常见模式是参数化父类 class A<T>并将属性定义为 val mapper: Mapper<T> .

这样,子类型就必须指定哪个 T他们在声明中使用:class B(...) : A<Animal>(...) ,以及看到 A<Animal> 的用户(即使不知道它实际上是 B<Animal> 也会安全地得到它的 mapper 作为 Mapper<Animal>

关于java - Kotlin 继承与泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46305481/

相关文章:

java - Spring security 在 AWS ThinkPHP 请求上部署了应用程序

使用 Kotlin 中的 Guava 的 toImmutableSortedMap 收集器时出现泛型错误

c++ - SFML 在实现绘制函数时从派生类转换不明确

java - jOOQ 和桥接表

java - 获取 ScrolledForm SWT 中的 x 坐标

java - 具有引用和原始类型的 isAssignableFrom

java - 使用泛型 Object[] 的 ClassCastException 无法转换

html - 为什么 text-decoration 会停止基于子元素定位的继承?

JavaScript:从父类(super class)实例内部创建子类

java - 访问heroku服务器上的文件或文件夹