繁体   English   中英

Java将子类实例数据传递给超类构造函数

[英]Java passing subclass instance data to superclass constructors

有人知道在调用超类构造函数之前,Java中是否有办法在子类中设置实例变量的值。 下面是我要完成的工作的简要示意图-根据子类类型,我需要以不同的方式设置超类中定义的实例变量,但我仍然希望能够共享通用的非构造函数代码子类的不同实例。

有什么干净的方法可以做到这一点,也许我缺少某种编码模式? 预先感谢您的任何想法。

public abstract class ConstraintSatisfactionProblem {

    final Set<Variable> variables;
    final Set<Constraint> constraints;

    public Foo() {
        this.variables = setupVariables();
        this.constraints = setupConstraints();
    }

    public abstract Set<Variable> setupVariables();

    public abstract Set<Constraint> setupConstraints();

    public Map<Variable, Constraint> solve() { ... }
}

public class WordSquare extends ConstraintSatisfactionProblem {

    final int size;
    final static Set<Character> domain = ...;

    public WordSquare() {
        super();         // can I simulate calling super() after setting this.value = 4?
        this.value = 4;
    }

    public Set<Variable> setupVariables() {
        this.variables = new HashSet<Variable>();
        for(int row = 0; row < size; ++row) {
            for(int col = 0; col < size; ++col) {
               variables.add(new Variable<Pair, Character>(new Pair(row, col), domain);
            }
        }
        return this.variables;
    }

    public Set<Constraint> setupConstraints() {
        // setup code specific to this problem
    }
}

public class Cryptarithmetic extends ConstraintSatisfactionProblem {

    final String problem;

    public Cryptarithmetic(String problem) {
        super();
        this.problem = problem;
    }

    public Set<Variable> setupVariables() {
        this.variables = new HashSet<Variable>();
        for(char c : problem.toCharArray()) {
            variables.add(new Variable<Character, Integer>(c, getDomain());
            }
        } 
        return this.variables;
    }

    public Set<Constraint> setupConstraints() {
        // setup code specific to this problem
    }
}

首先,请不要。

其次,这真的是一个非常糟糕的主意。 别。 考虑一下您想在更广泛的环境中做什么。

如果绝对必须这样做,则可以将其存储在ThreadLocal 您可以通过评估将结果传递到super()this()的表达式来调用(非实例)方法(这可能是您需要第二个私有构造函数且可能采用Void的唯一原因(大写的' V')参数)。 太邪恶了,我什至不打算写下代码。

在编辑的示例代码中,只需将集合传递到受保护的构造函数中即可。 如果您有许多参数,则某些子类可能对某些参数具有特殊性,则可能需要将所有参数包装到单个参数对象中。

只要您具有-target 1.4或更高版本(您应该这样做),还有另一种真正的骇人听闻的方法。 使子类成为内部类(可能是匿名的)。 调用超级构造函数之前,可以使用外部this和其他捕获的变量的引用。

public class Outer {
    // What a hack!
    private static abstract class Base {
        Base() {
            hello(); // Calling a virtual method in a constructor - poor form.
        }
        abstract void hello();
    }
    public static void main(String[] args) {
        // Do not do this.
        final String hi = "Hi!";
        new Base() {
            void hello() {
                // Really, don't do it.
                System.err.println(hi);
            }
        };
    }
}

将要运行的通用代码放在受保护的方法中,而不是在构造函数中。 您可以根据需要调用该方法。

在Java中,如果要调用基类的构造函数,则必须在子类的构造函数的第一行执行此操作。 因此答案是否定的,您不能在调用超类的构造函数之前设置this.value

但是您的子类的setup()方法已在超级类的构造函数中调用。 您为什么不在那里设定您的价值?

更新:对不起,我没有注意到您的“ setup()”方法返回一个值。 您可以做的是在您的超级类中创建一个抽象的init()方法,并在调用setup()方法之前在您的超级构造函数中对其进行调用。 通过这种方式,子类将被强制实现init() ,并且您会知道,这是在任何子类的成员用于您的超类之前对其进行初始化的地方。

话虽这么说,但这种方法并不会给您带来安全隐患。 当您从子构造函数调用超级构造函数时,子类实例才刚刚开始创建。 在安全地创建对象之前,它仍然需要在子构造函数中运行其余代码。

在这种情况下,超级构造函数继续在您正在创建的过程的子类上调用init()方法。 这意味着,如果采用方法,则必须特别注意init()类中的操作。

您绝对不应在构造函数中调用任何“外来”方法(即此类的可重写方法,或任何其他类的任何方法)形式。 只要对象没有完全初始化,您可能会看到类似的副作用。

在您的情况下,在子类构造函数中,甚至在将“值”设置为4之前调用super()。这意味着先调用超类构造函数,然后再调用“ setup”方法,而“值”仍位于0。

只有超类构造函数返回后,“值”才设置为4。那时为时已晚。

我建议将“ o1”变量设置为protected,以便子类可以自行设置其值。

就像其他人所说的,不要这样做。 如果要在这些类之间共享一些代码,请尝试包含/封装而不是继承。

public class Foo {

    private final Object o1;

    public Foo(Object o) {
        o1 = o;
    }

    public void complexMethodCommonToAllSubclassesOfFoo() { ... }
    }

public class Bar {

    private final int value;
    private final Foo foo;

    public Bar() {
        super(); 
        this.value = 4;
        this.foo = new Foo( new Object() ); // or whatever
    }

    // If you need to expose complexMethodCommonToAllSubclassesOfFoo to clients of this class, just add the method and delegate to foo like this
    public void complexMethodCommonToAllSubclassesOfFoo() {
        foo.complexMethodCommonToAllSubclassesOfFoo();
    }
}

我需要根据子类类型以不同的方式设置超类中定义的实例变量,但是我仍然希望能够在子类的不同实例之间共享通用的非构造函数代码。

在这种情况下,请在超类中创建一个受保护的构造函数,并在构造子类时将所有自定义值传递给它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM