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

时间:2011-12-13 17:25:35

标签: java polymorphism cryptarithmetic-puzzle

有人知道在调用超类构造函数之前,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
    }
}

6 个答案:

答案 0 :(得分:1)

首先,请不要。

其次,真的是一个非常糟糕的主意。别。想想你在更广泛的背景下想要做什么。

如果绝对必须这样做,可以将其存放在ThreadLocal中。您可以通过计算结果传递给super()this()的表达式来调用(非实例)方法(可能是您需要第二个私有构造函数的唯一原因,可能需要Void(资本'V')论点)。它太邪恶了,我甚至不打算写下代码。

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

还有另一个真正的hacky方法,只要你有-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);
            }
        };
    }
}

答案 1 :(得分:0)

将要运行的公共代码放在受保护的方法中,而不是放在构造函数中。如果你愿意,可以调用该方法。

答案 2 :(得分:0)

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

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

<强>更新 对不起,我没注意你的'setup()'方法返回一个值。您可以做的是在超类中创建一个抽象的init()方法,并在调用setup()方法之前在超级构造函数中调用它。这样子类就会被强制实现init(),你会知道这是在超级类中使用它们之前初始化任何子类成员的地方。

话虽如此,这种方法并不会强迫你安全。当您从子构造函数中调用超级构造函数时,子类实例才刚刚开始创建。在安全地创建对象之前,它仍然需要在子构造函数中运行其余的代码。

在这种情况下,超级构造函数会在你正在创建的子进程中调用init()方法。这意味着如果你采用方法,你必须要特别注意你在init()课程中所做的事情。

答案 3 :(得分:0)

你永远不应该打电话给任何&#34;外星人&#34;方法(即,此类的可重写方法,或来自任何其他类的任何方法)在构造函数中形成。只要对象未完全初始化,您可能会产生类似于您所看到的副作用。

在您的情况下,在子类构造函数中,甚至在&#34;值&#34;之前调用super();设置为4.这意味着,调用超类构造函数,然后调用&#34; setup&#34;方法,而&#34;值&#34;仍然是0。

只有超类构造函数返回一次,&#34;值&#34;设置为4.那时已经太晚了。

我建议的是设置&#34; o1&#34;变量为protected,以便子类可以自己设置它的值。

答案 4 :(得分:0)

像其他人说的那样,不要这样做。如果要在这些类之间共享一些代码,请尝试使用containment / encapsulation而不是继承。

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();
    }
}

答案 5 :(得分:0)

  

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

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