为什么在派生类中出现“继承的平台声明冲突”错误?

时间:2018-09-19 17:31:22

标签: android kotlin derived-class

具有接口(从依赖的SDK定义且无法进行更改,BaseDelegate也来自sdk)和基类:

interface ViewDelegate {

    fun getDataType() : String
    fun getItemViewType() : Int

    fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder
    fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: Data, position: Int)

    fun getClickHandler() : View.OnClickListener
    fun setClickHandler(clickHanlder: View.OnClickListener)
}

open class BaseDelegate(@JvmField var clickHandler: View.OnClickListener) : ViewDelegate {

    @JvmField var layoutId = R.layout.base_view

    override fun getClickHandler(): View.OnClickListener {
        return clickHandler
    }

    override fun setClickHandler(clickHanlder: View.OnClickListener) {
        clickHandler = clickHanlder
    }

    override fun getDataType(): String {
        return "Base_TYPE"
    }

    override fun getItemViewType(): Int {
        return 1000
    }

    override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder {
        return BaseViewHolder(parent.inflate(layoutId, false), clickHandler)
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: IData, position: Int) {
        (holder as? BaseViewHolder)?.bindView(item, position)
    }
}

很好。

但是,如果从基类中派生一个类,则会出错

class DerivedViewDelegate(clickHandler: View.OnClickListener) : BaseDelegate(clickHandler){

    init {
        layoutId = R.layout.child_view
    }

    override fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder {
        val vw = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false)
        return ChildViewHolder(vw, clickHandler)
    }
    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, item: Data, position: Int) {
        (holder as? ChildViewHolder)?.bindView(item, position)
    }
}

错误提示:

inherited platform declaration clash: The following declarations have same JVM signature (getClickHandler()Landroid/view$OnClickListner;)  fun <get-clickHandler>(): View.OnClickListener defined in DerivedViewDelegate fun getClickHandler(): View.OnClickListener defined in DerivedViewDelegate

inherited platform declaration clash: The following declarations have same JVM signature (setClickHandler(Landroid/view$OnClickListner;)V)  fun <set-clickHandler>(<set-?>: View.OnClickListener): Unit  defined in DerivedViewDelegate fun setClickHandler(clickHandler: View.OnClickListener): Unit defined in DerivedViewDelegate

在Java中很好:

class DerivedViewDelegate extends BaseDelegate {

    public DerivedViewDelegate(View.OnClickListener clickHandler) {
            super(clickHandler);
            layoutId = R.layout.child_view;
        }
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, Data item, int position) {
            ((ChildViewHolder )holder).onBindViewHolder(item, position);
}

@NotNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {

    View vw = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
    return new ChildViewHolder(vw, clickHandler);

}
}

1 个答案:

答案 0 :(得分:1)

如果删除@JvmField,则主要问题变得明显;如果将其从BaseDelegate中删除,那里也会出现相同的错误。

发生的事情是该字段创建了自己的getter和setter,它们与父类中的方法冲突。在派生类上使用@JvmField无效;它仍然显示相同的错误。

因此,除了声明getter和setter之外,还有一个相对简单的解决方案。 Kotlin中的接口可以具有字段。无论如何,根据我所知道的,它们会被编译为getter和setter。无论如何,主要要点是它提供了一种简单的方法来处理接口中的必需变量。

因此,将您的界面更改为此:

interface ViewDelegate {
    var clickHandler: View.OnClickListener

    fun getDataType() : String
    fun getItemViewType() : Int

    fun onCreateViewHolder(parent: ViewGroup): RecyclerView.ViewHolder
    fun onBindViewHolder(holder: RecyclerView.ViewHolder, data: ClipData.Item, position: Int)

}

请注意,我删除了getter和setter方法,只是将其替换为变量。

现在,在BaseDelegate类中,您必须覆盖变量:

class BaseDelegate(override var clickHandler: View.OnClickListener) : ViewDelegate

@JvmField不见了。还要记住,在课堂上删除您的吸气剂和吸气剂,您将不再需要它们。删除@JvmField之后,BaseDelegate和ViewDelegate中的getter和setter除了添加字段外,还应该编译。


由于您不能更改界面(这是您最好的选择),因此还有另一个选择。除非明确定义了私有字段,否则它们不会使用getter和setter。举个例子:

class Test(){
    var x: Int = 0
    fun something(){
        x = 3
    }
}

它编译为:

public final class Test {
   private int x;

   public final int getX() {
      return this.x;
   }

   public final void setX(int var1) {
      this.x = var1;
   }

   public final void something() {
      this.x = 3;
   }
}

注意如何直接引用x。现在,如果我将其设为私有:

class Test(){
    private var x: Int = 0
    fun something(){
        x = 3
    }
}

发生这种情况:

public final class Test {
   private int x;

   public final void something() {
      this.x = 3;
   }
}

获取器和设置器不见了。但是,如果我明确声明它们:

class Test(){
    private var x: Int = 0
        get() = field
        set(v) {
            field = v;
        }
    fun something(){
        x = 3
    }
}

它产生:

public final class Test {
   private int x;

   private final int getX() {
      return this.x;
   }

   private final void setX(int v) {
      this.x = v;
   }

   public final void something() {
      this.setX(3);
   }
}

公共变量也是如此;如果声明了getter并且是自定义的(不仅是get set),那么它将使用.setX(v)而不是this.x = v

这如何适用于您的情况?

您对生成的getter和库声明的getter有冲突的声明。因此,由于除非明确定义了私有字段,否则私有字段不会创建getter和/或setter,因此请将您的var更改为private:

open class BaseDelegate(private var clickHandler: View.OnClickListener) : ViewDelegate

请注意,这会破坏属性访问语法; ,您将无法调用derivedViewDelegateInst.clickHandler,并且即使在科特林