java - 在基类构造函数中调用虚方法

标签 java c# c++ constructor

我知道从基类构造函数调用虚方法可能很危险,因为子类可能不处于有效状态。 (至少在 C# 中)

我的问题是,如果虚拟方法是初始化对象状态的方法呢?这是一种好的做法还是应该是一个两步过程,首先创建对象,然后加载状态?

第一个选项:(使用构造函数初始化状态)

public class BaseObject {
    public BaseObject(XElement definition) {
        this.LoadState(definition);
    }

    protected abstract LoadState(XElement definition);
}

第二个选项:(使用两步过程)

public class BaseObject {
    public void LoadState(XElement definition) {
        this.LoadStateCore(definition);
    }

    protected abstract LoadStateCore(XElement definition);
}

在第一种方法中,代码的使用者可以使用一条语句创建和初始化对象:

// The base class will call the virtual method to load the state.
ChildObject o = new ChildObject(definition)

在第二种方法中,消费者必须创建对象然后加载状态:

ChildObject o = new ChildObject();
o.LoadState(definition);

最佳答案

(这个答案适用于 C# 和 Java。我相信 C++ 在这个问题上的工作方式不同。)

在构造函数中调用虚方法确实很危险,但有时它可以得到最干净的代码。

我会尽量避免它,但不会极大地弯曲设计。 (例如,“稍后初始化”选项禁止不变性。)如果您确实在构造函数中使用了虚方法,则非常强烈地记录它。只要参与的每个人都知道它在做什么,它就不应该引起太多很多问题。不过,我会尝试限制可见性,就像您在第一个示例中所做的那样。

编辑:这里重要的一件事是 C# 和 Java 在初始化顺序上有所不同。如果您有这样的类(class):

public class Child : Parent
{
    private int foo = 10;

    protected override void ShowFoo()
    {
        Console.WriteLine(foo);
    }
}

Parent 构造函数调用 ShowFoo 的地方,在 C# 中将显示 10。在 Java 中的等效程序将显示 0。

关于java - 在基类构造函数中调用虚方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/448258/

相关文章:

c# - 我是否只需要在 Mock 对象上显式设置预期的返回值?

c++ - OpenCV 从 B/W 转换为 RGB

c++ - 传递参数时如何更新C++可选参数?

java - 如何分别使用 JBoss Logging 记录 JBoss 服务器特定日志和使用 log4j 记录应用程序特定日志?

java - OkHttp 客户端每秒执行的最大可能请求数

c# - 创建多级 MemberExpression

c# - WIA 设置页面大小不起作用

c++ - 在英特尔编译器的特定位置禁用警告

java - 如何增加 STS(Spring Tool Suite)内存大小?

java - Spring Integration Bridge 注解配置导致 BeanCurrentlyInCreationException