运行这段代码将打印 null
public class Weird {
static class Collaborator {
private final String someText;
public Collaborator(String text) {
this.someText = text;
}
public String asText() {
return this.someText;
}
}
static class SuperClass {
Collaborator collaborator;
public SuperClass() {
initializeCollaborator();
}
protected void initializeCollaborator() {
this.collaborator = new Collaborator("whatever");
}
public String asText() {
return this.collaborator.asText();
}
}
static class SubClass extends SuperClass {
String someText = "something";
@Override
protected void initializeCollaborator() {
this.collaborator = new Collaborator(this.someText);
}
}
public static void main(String[] arguments) {
System.out.println(new Weird.SubClass().asText());
}
}
(这里也是GitHub Gist)
现在,我知道为什么会发生这种情况(这是因为超类的字段已初始化,然后在子类的字段初始化之前调用超类的构造函数)
问题是:
答案 0 :(得分:3)
设计有什么问题:你从构造函数中调用实例方法,然后在子类中重写它。不要那样做。理想情况下,只从构造函数体调用private或final实例方法或静态方法。您还在SuperClass
之外公开了一个字段(这是一个实现细节),这不是一个好主意 - 但编写受保护的setCollaborator
方法并从initializeCollaborator
调用该方法会给出同样的问题。
至于如何解决它 - 你真正想要达到的目标并不是很清楚。为什么你需要initializeCollaborator
方法呢?可以有各种方法来解决这个问题,但它们实际上取决于 eaxctly 你想要实现的目标。 (哎呀,在某些情况下,最好的解决方案是不要首先使用继承。首选组合而不是继承,以及所有这些:)
答案 1 :(得分:1)
不使用intializeCollaborator方法,而是将Collaborator作为构造函数的参数,并使用super(new Collaborator(..))从子项中调用它。
答案 2 :(得分:1)
我的设计问题是someText
字符串应该是Collaborator对象或SubClass的显式依赖项(或“协作者”),或者显式是全局上下文的一部分(所以是常量或共享上下文对象的属性)。
理想情况下,Collaborator应负责检索其依赖项;或者,如果SubClass对此负责,它应该someText
作为依赖项(即使它始终初始化为相同的值),并且只在设置someText时初始化Collaborator。
从概念上讲,设计中对象之间的依赖关系强加了初始化的部分排序。实现此排序的机制应始终在您的设计中明确,而不是依赖于Java语言的实现细节。
(过度设计)的例子:
interface ICollaboratorTextLocator {
String getCollaboratorText();
}
class ConstantCollaboratorTextLocator implements ICollaboratorTextLocator {
String text;
ConstantCollaboratorTextLocator(String text) {
this.text = text;
}
}
class SuperClass {
Collaborator collaborator;
public setCollaboratorTextLocator(ICollaboratorTextLocator locator) {
collaborator = new Collaborator(locator.getCollaboratorText());
}
SuperClass() {
setCollaboratorTextLocator(new ConstantCollaboratorTextLocator("whatever"));
}
}
class SubClass {
String text = "something";
SubClass() {
setCollaboratorTextLocator(new ConstantCollaboratorTextLocator(text));
}
}
(现在请原谅,在写完ConstantCollaboratorTextLocator
之后,我需要站在瀑布下。)