当前位置: 首页 > 知识库问答 >
问题:

使用类委托时,是否有办法覆盖委托对象的方法使用的成员?

巴宏恺
2023-03-14

在Kotlin中使用类委托时,可以覆盖成员。然而,关于代表团的参考页上说:

但是,请注意,以这种方式重写的成员不会从委托对象的成员中调用,委托对象只能访问其自己的接口成员实现。

我想重写委托对象的方法使用的属性,以便委托对象的方法调用此重写属性。正如文档所述,用override关键字覆盖属性并不能实现这一点。有什么方法可以让我实现这种行为吗?如果不是,这是否表明我应该改用继承?

这是一个代码示例:

interface Base {
    val message: String
    fun print()
}

class BaseImpl(val x: Int) : Base {
    override val message = "BaseImpl: x = $x"
    override fun print() { println(message) }
}

class Derived(b: Base) : Base by b {
    // This property is not accessed from b's implementation of `print`
    override val message = "Message of Derived"
}

fun main(args: Array<String>) {
    val b = BaseImpl(10)
    val derived = Derived(b)
    derived.print()
}

这段代码打印“BaseImpl:x=10”,但我希望它打印“导出的消息”。

共有2个答案

赖绪
2023-03-14
interface BaseInterface {
    fun doSomething()
    fun doSomethingElse()
}

class BaseImpl : BaseInterface {
    override fun doSomething() = println("doSomething in BaseImpl")
    override fun doSomethingElse() = println("doSomethingElse in BaseImpl")
}

class Derived : BaseInterface by BaseImpl() {
    override fun doSomething() = println("doSomething in Derived")
}

fun main() {
    val obj = Derived()
    obj.doSomething()
    obj.doSomethingElse()
}

做派生的东西

BaseImpl中的doSomethingElse

房星光
2023-03-14

问题出在生成的代码上:

public final class BaseImpl implements Base {
   @NotNull
   private final String message;
   private final int x;

   @NotNull
   public String getMessage() {
      return this.message;
   }

   public void print() {
      String var1 = this.getMessage();
      System.out.println(var1);
   }

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

   public BaseImpl(int x) {
      this.x = x;
      this.message = "BaseImpl: x = " + this.x;
   }
}
public interface Base {
   @NotNull
   String getMessage();

   void print();
}
public final class Derived implements Base {
   @NotNull
   private final String message;
   // $FF: synthetic field
   private final Base $$delegate_0;

   @NotNull
   public String getMessage() {
      return this.message;
   }

   public Derived(@NotNull Base b) {
      Intrinsics.checkParameterIsNotNull(b, "b");
      super();
      this.$$delegate_0 = b;
      this.message = "Message of Derived";
   }

   public void print() {
      this.$$delegate_0.print();
   }
}

我花了一段时间才发现它,但要点是:

委托并不意味着扩展特定类型;它意味着覆盖Base(在本例中)接口,并将未被覆盖的事件发送到委托的类。这里有两件事需要密切关注:

public void print() {
   this.$$delegate_0.print();
}

public final class Derived implements Base {

这是什么意思?这意味着Derived不会以任何方式覆盖BaseImpl。为了说明我的意思,请看以下代码:

interface Base {
    val message: String
    fun print()
}

open class BaseImpl(val x: Int) : Base { // This needs to be `open` to override
    override val message = "BaseImpl: x = $x"
    override fun print() { println(message) }
}

class Derived(x: Int) : BaseImpl(x) {
    // This property is not accessed from b's implementation of `print`
    override val message = "Message of Derived"
}

fun main(args: Array<String>) {
    val derived = Derived(10)
    derived.print()
}

它会打印派生的消息。为什么?因为现在你实际上覆盖了BaseImpl。反编译代码,记住我之前告诉你要密切注意的两件事:

public final class Derived extends BaseImpl {
   @NotNull
   private final String message = "Message of Derived";

   @NotNull
   public String getMessage() {
      return this.message;
   }

   public Derived(int x) {
      super(x);
   }
}

您可能会看到print方法不见了;这是因为您没有覆盖它。此外,它现在扩展了BaseImpl而不是实现Base。对getMessage方法的任何调用(您可以看到在print方法中调用)都将“重定向”到被覆盖的方法,而不是基类中的方法。

如果在Java中这样做,而不是使用直接调用字段的getter,它将不起作用,因为在Java中无法重写变量。它在Kotlin开箱即用中工作的原因是,正如您在反编译代码中看到的,它使用方法。

如何解决这个问题取决于您。如果您仍然想使用委托属性,您需要覆盖Derive类中的print方法。因为,正如我之前提到的,DeriveBaseImpl之间没有实际关系,除了有一个共享的父级。但是Derive不是BaseImpl的子级。

因此,如EpicPandaForce所述重写getMessage(),将不起作用。另外,通过执行override val message= 您确实生成了一个覆盖的getter,我的第二个示例显示了这一点。

太长别读:Base by b实现Base,并将对print的调用发送到委托的BaseImplDerive不是BaseImpl的子级,因此,BaseImpl无法调用Deriated中的getMessage()getter,因此打印自己的消息。

 类似资料:
  • 我在使用Byte Buddy时遇到了一个简单的问题,下面是我的代码: 我希望工作并将调用转发到受人尊敬的拦截器实例,但是我得到这个异常: 最奇怪的部分在异常消息的最后: 我做错了什么?

  • 问题内容: 有人可以解释何时以及何时不使用Swift中的委托指针进行“弱”分配,为什么? 我的理解是,如果您使用的协议未定义为类,则无法,也不想将您的委托指针分配给弱。 但是,当您的协议定义为类类型协议时,您是否要将委托设置为弱指针? 我对么?在Apple的快速指南中,类协议示例没有使用弱分配,但是在我的测试中,如果没有弱引用我的委托人,我会看到强参考周期。 问题答案: 通常,使类协议(如用关键字

  • 本文向大家介绍C#中的委托使用,包括了C#中的委托使用的使用技巧和注意事项,需要的朋友参考一下 从今天开始写关于C#的系列文章,本篇文章主要讲解C#中的委托使用。 委托其实就是一种数据类型,和int,string是一样的概念。 如果要把一个字符串赋值给一个变量,用string声明一个变量即可。如果要把一个方法赋值给一个变量,那么用什么关键字呢?当然就是用委托了,所以用委托声明的变量就可以接受一个方

  • 本文向大家介绍C#中委托(Delegates)的使用方法详解,包括了C#中委托(Delegates)的使用方法详解的使用技巧和注意事项,需要的朋友参考一下 1. 委托是什么? 其实,我一直思考如何讲解委托,才能把委托说得更透彻。说实话,每个人都委托都有不同的见解,因为看问题的角度不同。个人认为,可以从以下2点来理解:  (1) 从数据结构来讲,委托是和类一样是一种用户自定义类型。  (2) 从设计

  • ILRuntime中使用委托 如果只在热更新的DLL项目中使用的委托,是不需要任何额外操作的,就跟在通常的C#里那样使用即可 如果你需要将委托实例传给ILRuntime外部使用,那则根据情况,你需要额外添加适配器或者转换器。 需要注意的是,一些编译器功能也会生成将委托传出给外部使用的代码,例如: Linq当中where xxxx == xxx,会需要将xxx == xxx这个作为lambda表达式

  • 生成器委托 PHP7中支持delegating generator,可以自动展开subgenerator; A “subgenerator” is a Generator used in the portion of the yield from syntax. 我们需要在PHP5支持子生成器,将子生成器最后yield值作为父生成器yield表达式结果,仅只需要加两行代码,递归的产生一个Async