有人知道在调用超类构造函数之前,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
}
}
答案 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)
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)
我需要根据子类类型设置超类中定义的实例变量,但我仍然希望能够在子类的不同实例之间共享公共非构造函数代码。
在这种情况下,在超类中创建一个受保护的构造函数,并在构造子类时将所有自定义值传递给它。