1

有人知道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
    }
}
4

6 回答 6

1

首先,请不要。

其次,这确实是一个非常糟糕的主意。不。在更广泛的背景下考虑您正在尝试做的事情。

如果你绝对必须这样做,你可以把它藏在一个ThreadLocal. 您可以通过评估一个表达式来调用(非实例)方法,该表达式的结果被传递给super()or (可能是您需要第二个可能采用(大写“V”)参数的this()私有构造函数的唯一原因)。Void太邪恶了,我什至不会写下代码。

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

还有另一种非常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);
            }
        };
    }
}
于 2011-12-13T17:32:48.973 回答
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();
    }
}
于 2011-12-13T18:06:38.340 回答
0

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

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

于 2011-12-13T18:54:50.787 回答
0

将要运行的公共代码放在受保护的方法中,而不是放在构造函数中。需要时调用该方法。

于 2011-12-13T17:33:48.747 回答
0

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

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

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

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

在这种情况下,超级构造函数会去调用init()你刚刚在创建过程中的子类的方法。这意味着,如果你采用方法,你必须格外小心你在init()课堂上所做的事情。

于 2011-12-13T17:35:21.607 回答
0

您永远不应该在构造函数中调用任何“外星人”方法(即此类的可覆盖方法,或任何其他类的任何方法)形式。只要对象未完全初始化,您就可能会产生像您看到的那样的副作用。

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

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

我建议将“o1”变量设置为受保护,以便子类可以自己设置其值。

于 2011-12-13T17:36:25.913 回答