【问题标题】:"Property type is not a subtype of overridden abstract val" on multiple-inherited field多重继承字段上的“属性类型不是覆盖抽象 val 的子类型”
【发布时间】:2018-02-02 21:30:59
【问题描述】:

有时,一个类型被声明为实现两个具有相同名称的抽象属性的接口,但是当我将有界类型参数移动到顶级抽象超类并在不同对象中对其进行子类化时,该类会覆盖使用子类的类型参数时,两个超接口上的抽象属性都无法编译。

生成的接口和抽象类:

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

一个生成的对象的例子,它覆盖了两个同名的超级接口属性:

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&lt;T&gt;posts 之类的字段提供了一组单独的接口,但为简洁起见,我将其省略了)

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

【问题讨论】:

    标签: java android jvm polymorphism kotlin


    【解决方案1】:

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

    在接口和抽象类中将Config&lt;String, BasePostsArgs&gt; 更改为Config&lt;String, out BasePostsArgs&gt;。然后,您将能够使用 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 在其类型参数上是不变的,那么如果 T1T2 是不是同一类型(在您的情况下,T1 := BasePostsArgsT2 := Organization.PostsArgs)。但是,当您使用out 投影时,只要T1T2 的子类型,A&lt;T1&gt; 就会成为A&lt;T2&gt; 的子类型。您可以使用基类型中属性的子类型覆盖val(但这不适用于vars)。

    【讨论】:

    • Intellij 甚至在建议它,我不知道我是怎么错过的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 2017-02-23
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 2014-11-21
    相关资源
    最近更新 更多