【问题标题】:How to execute subclass's inherited initialize method after construction?构造后如何执行子类继承的初始化方法?
【发布时间】:2017-11-28 22:29:41
【问题描述】:

考虑以下代码:

public abstract class Command {

    public Command() {
        configure();
    }

    public void configure() {
    }

}


public abstract class ComplexCommand extends Command {

    private ArrayList<String> commands = new ArrayList<>();

    @Override
    public void configure() {
        System.out.println(commands);
    }

}

configure() 方法旨在由 Command 或 ComplexCommand 的子类实现,以修改命令的属性,因此预期功能是在构造实现子类后在实现子类中执行 configure() 方法(命令变量已初始化)。然而,在本例中调用new ComplexCommand() 将导致null 被打印到控制台。如果我错了,请纠正我,但这似乎是因为子类构造函数中隐含的super() 在子类字段初始化之前执行。

以下是如何使用这些类的示例:

public class MyTestCommand extends Command {

    @Override
    public void configure() {
        setUsage("Usage: /test <target>");
        setDescription("This is a test command");
    }

}

玩弄这个,我确实想出了一种解决问题的方法,但我想知道是否有人有更好的解决方案。我的解决方法是通过创建一个允许/禁用从父级执行configure() 然后从子级运行它来覆盖父级构造函数。

public abstract class Command {

    public void configure() {
    }

    public Command() {
        configure();
    }

    protected Command(boolean configure) {
        if (configure) {
            configure();
        }
    }

}

public abstract class ComplexCommand extends Command {

    private ArrayList<String> commands = new ArrayList<>();

    @Override
    public void configure() {
        System.out.println(commands);
    }

    public ComplexCommand() {
        super(false);
        configure();
    }

}

在此示例中,configure() 在子类的字段已初始化并显示 [] 后正确运行。无论如何,它看起来仍然很老套,一开始可能会令人困惑。除了我所做的之外,还有更好的方法吗?

【问题讨论】:

  • 什么你不只是从超类的构造函数中删除configure();
  • @Yahya 我希望用户能够针对不同的用例为任一类实现和使用 configure()。
  • 既然您的 Command 类是抽象的,那么 configure 方法也是抽象的不是很有意义吗?

标签: java class inheritance constructor initialization


【解决方案1】:

在我看来,这整个想法是有缺陷的,因为您只是使用 configure 方法代替子构造函数。一点用处都没有。

为什么首先需要配置?所以子类可以覆盖你说的。但是他们已经可以覆盖构造函数了,还有什么意义呢?

public abstract class Command {   

    public Command() {
        // Do things to initialize Command
    }    
}

public abstract class ComplexCommand extends Command {

    private ArrayList<String> commands;

    public ComplexCommand() {
        super();
        // Do things to initialize ComplexCommand
        this.commands = new ArrayList<>();
        System.out.println(this.commands);
    }    
}

public class MyTestCommand extends Command {

    public MyTestCommand() {
        super();
        setUsage("Usage: /test <target>");
        setDescription("This is a test command");
    }    
}

【讨论】:

  • 这适用于我正在做的事情,谢谢。在重构代码时,我太忙于删除构造函数。
  • @Yahya 您刚刚建议从超类的构造函数中删除 configure() 。如果我这样做了,使用 Command 的实现将不会执行其配置方法。
  • @kmecpp 你在开玩笑吗?!看看上面接受的答案。从超类构造函数中删除configure() 将实现完全相同的效果!您的问题甚至不清楚您想要实现的目标!上面的答案只是在OOP中实现继承的经典普通方式。令人难以置信的是,您无法弄清楚您只想要程序的基础知识。我今天花了几个小时尝试使用Reflection 实现这一目标。最后你的意思是一个简单的继承的基本实现!
  • @Yahya 哈哈抱歉。你的评论也不清楚。如果我只是从超类构造函数中删除了 configure() ,它就不会起作用。您从未说过完全不使用该方法。我选择了这个答案,因为尽管改变了 API 的样式(使用构造函数而不是单独的方法),它恰好适用于我试图完成的任务。如果你能找到一个更好的解决方案来解决我原来的问题,它保留了 configure() 方法,我会很乐意改变我接受的答案:)
猜你喜欢
  • 2018-01-30
  • 2014-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-12
  • 2013-12-13
  • 1970-01-01
相关资源
最近更新 更多