在调用超类的构造函数之前,有没有办法在 Java 中初始化子类的成员变量? [英] Is there any way to initialize member variables of a subclass in Java before the superclass' constructor is called?

查看:52
本文介绍了在调用超类的构造函数之前,有没有办法在 Java 中初始化子类的成员变量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要这个是因为超类中的构造函数正在调用一个在子类中被覆盖的方法.该方法返回一个传递给子类的构造函数的值.但是超类构造函数必须在子类构造函数之前调用,所以我没有机会保存传入的值.

I need this because the constructor in the superclass is calling a method which is overridden in the subclass. The method returns a value which is passed to the subclass' constructor. But the superclass constructor must be called before the subclass constructor, so I have no chance to save the value passed in.

推荐答案

从超类构造函数调用重写的方法根本行不通 - 不要这样做. 超类构造函数必须始终在子类之前完成.当超类构造函数正在执行时,有问题的对象是超类的(半初始化)实例,而不是子类!因此,如果您尝试从构造函数调用任何重写的函数,它可能依赖的子类字段尚未初始化(正如您所观察到的).这是类设计的基本事实,没有解决方法.

Calling an overridden method from the superclass constructor is simply not going to work - don't do it. The superclass constructor must always finish before that of the subclass. While the superclass constructor is executing, the object in question is a (half initialized) instance of the superclass, not the subclass! So if you try to call any overridden function from the constructor, the subclass fields it may depend on are not yet initialized (just as you have observed). This is a fundamental fact of class design, and there is no workaround.

Effective Java 2nd 中所述.编辑(第 4 章,第 17 项):

As explained in Effective Java 2nd. Ed. (Chapter 4, Item 17):

有 [...] 类必须遵守的限制才能允许遗产.构造函数不得直接调用可覆盖的方法或间接.如果违反此规则,将导致程序失败.这超类构造函数在子类构造函数之前运行,所以子类中的覆盖方法将在子类之前被调用构造函数已经运行.如果覆盖方法依赖于任何初始化由子类构造函数执行,该方法不会像预期.

There are [...] restrictions that a class must obey to allow inheritance. Constructors must not invoke overridable methods, directly or indirectly. If you violate this rule, program failure will result. The superclass constructor runs before the subclass constructor, so the overriding method in the subclass will get invoked before the subclass constructor has run. If the overriding method depends on any initialization performed by the subclass constructor, the method will not behave as expected.

如果您可以更改超类实现,请尝试将虚拟函数的调用移出构造函数.实现此目的的一种方法是使用工厂方法:

If you can change the superclass implementation, try moving the call to the virtual function out of the constructor. One way to achieve this is using a Factory Method:

class Super {
    public void init() { ... }
}

class Subclass extends Super {
    private Subclass() { super(); ... }
    public void init() { super.init(); ... }
    public static Subclass createInstance() {
        Subclass instance = new Subclass();
        instance.init();
        return instance;
    }
}

注意Subclass 的构造函数是私有的,以确保它只能通过createInstance() 实例化,因此实例总是被正确初始化.OTOH 这也阻止了进一步的子类化.但是,无论如何都不建议对具体类进行子类化 - 打算子类化的类应该是抽象的(在这种情况下使用 protected 构造函数).当然,任何进一步的子类还必须具有非公共构造函数和静态工厂方法,它们会努力调用 init()...

Note that the constructor of Subclass is private to ensure that it can only be instantiated via createInstance(), thus instances are always initialized properly. OTOH this also prevents further subclassing. However, subclassing a concrete class is not recommended anyway - a class meant to be subclassed should be abstract (with a protected constructor in this case). And of course, any further subclasses must also have non-public constructors and static factory methods which diligently call init()...

这篇关于在调用超类的构造函数之前,有没有办法在 Java 中初始化子类的成员变量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆