“多重继承的字段上的属性类型不是重写的抽象val的子类型”

时间:2017-08-24 21:24:10

标签: java android jvm polymorphism kotlin

有时,声明一个类型实现2个接口,这两个接口都具有相同名称的抽象属性,但是当我将有界类型参数移动到顶层抽象超类并将其子类化为不同对象时,该类重写了当为子类使用类型参数时,两个超接口上的抽象属性都无法编译。

生成的接口和抽象类:

interface Actor : Type {
  val login: Stub<String>
  val posts: Config<String, BasePostsArgs>
}

interface SomeConflict : Type {
  val posts: Config<String, BasePostsArgs>
}

abstract class BasePostsArgs(
  args: ArgBuilder = ArgBuilder.create<String, BasePostsArgs>()) 
  : ArgBuilder by args

生成的对象的一个​​示例,它覆盖了具有相同名称的2个超级接口属性:

object Organization : Type, SomeConflict, Actor {

  override val login: Stub<String> = stub() 

  override val posts: Config<String, Organization.PostsArgs> = configStub(PostsArgs())

  class PostsArgs(args: ArgBuilder = ArgBuilder.create<String, PostsArgs>()) 
    : BasePostsArgs(args) {

    fun first(value: Int): PostsArgs = apply { addArg("size", value) }
    fun since(value: Date): PostsArgs = apply { addArg("since", value) }
  }
}

然后是API的接口:

interface Type {
  fun <T> stub(): Stub<T> = StubImpl<T, ArgBuilder>()

  fun <T, A : ArgBuilder> configStub(argBuilder: A): Config<T, A> = StubConfigImpl(argBuilder)
}

interface Config<T, A : ArgBuilder> {
  fun config(): A
}

interface ArgBuilder {
  fun addArg(name: String, value: Any): ArgBuilder
  fun <T> build(): Stub<T>

  companion object {
    fun <T, A: ArgBuilder> create(): ArgBuilder = InternalImplementation<T, A>() as A
  }
}

为了在实现接口但需要不同参数的类型上的不同字段具有多态性,所以我可以这样声明它们:

class OrgPostsQuery(
  amount: Int = 100, 
  from: Date = Date.from(Instant.now())) : Model<Organization> {

  val posts by super.model.config()
    .first(1000)
    .since(from)
    .build()

}

(对于List<T>这样的字段,posts有一组单独的接口,但为了简洁,我将其留作了出去)

我做错了什么?或者这不可能吗?

1 个答案:

答案 0 :(得分:1)

为了能够使用类型参数的子类型覆盖通用val,您需要使用out-projection

在两个接口和抽象类中将Config<String, BasePostsArgs>更改为Config<String, out BasePostsArgs>。然后,您将能够使用BasePostArgs的子类型,其中BasePostArgs是预期的。

interface Actor : Type {
    val posts: Config<String, out BasePostsArgs>
}

interface SomeConflict : Type {
    val posts: Config<String, out BasePostsArgs>
}

object Organization : Type, SomeConflict, Actor {
    override val posts: Config<String, Organization.PostsArgs> = configStub(PostsArgs())

    /* ... */
}

您得到的错误是由于,如果某个类型A对其类型参数不变,那么A<T1>A<T2>永远不会是T1T2的子类型T1 := BasePostsArgs 1}}和T2 := Organization.PostsArgs的类型不同(在您的情况下,outA<T1>)。但是当您使用A<T2> - 投影时,只要T1T2的子类型,val就会成为var的子类型。并且您可以使用基类型中的属性的子类型覆盖select customer,productlist from table_name where instr(substr(productlist,1,length(productlist)-1),',')=0; (但这对dtAllStudentMarksDetail s不起作用。)