【问题标题】:Java Inheritance with Lambdas使用 Lambda 进行 Java 继承
【发布时间】:2021-07-14 04:26:07
【问题描述】:

我正在尝试使超类(抽象或接口)成为 ArrayList 中的引用类型(定义空 lambda)...并且实现该超类/接口的子类具有不同的 lambda表达式来隐藏超类的 null lambda。但最终发生的是,调用子类 lambda 只会调用超类的 null lambda!

示例代码:

public abstract class AbstractAction {
    Consumer<AbstractAction> behavior = state -> {
        System.out.println("AbstractAction: do nothing");
    };
}
public class IfTrue extends AbstractAction {
    Boolean var = true;
    Consumer<IfTrue> behavior = state -> {
        if (state.var == true) state.var = false;
        System.out.println("IfTrue: " + var);
    };
}
public class Compare extends AbstractAction {
    Boolean var1 = true;
    Boolean var2 = true;

    Consumer<Compare> behavior = state -> {
        if (state.var1 == state.var2) state.var1 = false;
        System.out.println("IfTrue: " + var1 + " " + var2);
    };
}
public class ActionList {
    List<AbstractAction> list = new ArrayList<>();

    public void addAction(AbstractAction abstractAction) {
        list.add(abstractAction);
    }

    public void runActions() {
        for (AbstractAction a : list) {
            a.behavior.accept(a);
        }
    }
}
public class Main {
    public static void main(String[] args) {
        ActionList list = new ActionList();
        list.addAction(new IfTrue());
        list.addAction(new Compare());
        list.runActions();
    }
}

结果(显示正在运行的 AbstractAction lambda,而不是子类):

AbstractAction: do nothing
AbstractAction: do nothing

但我希望看到:

IfTrue: true
Compare: false true

我也尝试过创建一个接口,但是我不能在每个子类中拥有不同数量的成员变量,否则我会收到 Actionable 接口没有这些成员的编译时错误。但即使我确实为 Actionable 接口提供了这些变量,我也会得到相同的结果。运行 Actionable.behavior lambda 而不是子类实现。

public interface Actionable {
    Boolean var = true;
    Boolean var1 = true;
    Boolean var2 = true;

    Consumer<Actionable> behavior = state -> {
        System.out.println("AbstractAction: do nothing");
    };
}

有没有办法隐藏 AbstractAction 或 Actionable.behavior lambda?还是我在想这个问题都错了?我真的希望能够用不同的行为/lambda 替换 Action 对象,以将操作与执行过程本身分离。

【问题讨论】:

  • 我不明白你为什么要使用 lambdas 和 Consumerbehaviour 不能只是一个方法吗?如果你正在做a.behavior.accept(a);,为什么它甚至需要一个参数?你有没有打算给它自己以外的任何东西?如果是这样,你怎么能确定你给它的是正确的类型?
  • @Sweeper 是的,我应该提到原因……我尝试了使用实例方法的方法,但在我的应用程序中,每个方法调用都会增加我的执行时间毫秒数,而这需要执行的业务案例时间尽可能快。我将子类本身作为参数传递的原因是,我可以在每个子类上拥有尽可能多的成员,而不必担心调用每个子类所需的不同数量的参数。 ActionList.runActions() for 循环。
  • 嗯...... lambdas 将如何帮助解决这个问题?如果有的话,我认为 lambdas 有一点 more 开销。您确定 this 是您的程序所做的所有事情中的瓶颈吗?
  • 也许不是。我假设 Lambdas invokeDynamic 或行为的静态方法会减少 GC 活动和每次 ActionList.runActions() 必须运行时实例化实例方法所花费的时间(可能需要每 0.01 毫秒运行一次)。你能想到另一种方法吗?我知道这有点像命令模式,但我试图尽量减少方法调用。
  • Lambda 基本上是匿名合成类的方法。把一个东西变成一个 lambda 并不能消除方法调用;它只是将其隐藏在其他地方。如果您的用例是处理器密集型的,以至于 方法调用 的存在成为瓶颈,那么您不应该使用 Java;你应该使用 C。流行的视频游戏是用 Java 编写的,你最好相信像 Minecraft 这样的东西每一帧都有 ton 的方法调用。

标签: java inheritance lambda


【解决方案1】:

只有实例方法可以被覆盖。实例变量永远不能被覆盖。如果子类中有一个与超类中的实例变量同名的实例变量,那么从子类中的代码的角度来看,它将简单地从超类中隐藏实例变量。但是它们仍然作为两个单独的变量存在,并且子类的每个实例仍然包含两个单独的实例变量。使用超类类型引用实例的代码仍然可以使用它来引用超类实例变量。

当然,你可以只在超类中保留一个实例变量,而在子类构造函数或实例初始化器中,你可以只从超类中分配给那个实例变量(而不是在子类中声明一个新的实例变量) .不过我还是不知道这个设计是否有意义。

【讨论】:

  • 好的好的。说得通。关于引用超类的好技巧。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-15
  • 2023-03-20
  • 1970-01-01
  • 2016-02-15
  • 2012-02-19
  • 2015-03-20
  • 2020-06-15
相关资源
最近更新 更多