在super()之前调用子属性?

时间:2013-07-24 08:26:52

标签: java

我主要使用动态语言 - 我刚刚开始使用Java,我正在努力使用静态模式。

根据我的理解,子类的构造函数中的第一个调用必须是它的父类。这很好,但是我需要在子节点的构造函数中引用子节点中设置实例变量...当然,这会创建一个catch-22。 (需要在调用parent之前在子节点中设置变量,但需要在child中设置变量之前调用parent)。

我确信我正在破坏某种静态语言模式或法律......我只是不确定是哪一种,或者如何重新设计它。任何帮助赞赏。简化下面的例子:

Class Race {

  public Race(Venue event_venue) {
    greeting();
  }

  public void greeting() {
    String event_greeting = String.format("The next event is: %s", getName());
    System.out.println(event_greeting);
  }

  public String getName() {
    return getClass().getSimpleName();
  }
}

Class Sprint extends Race {
  private int event_distance;

  public Sprint(Venue event_venue, int distance) {
    // super has to be the first call
    super(event_venue);
    // but I need to set event_distance to reference getName() in parent constructor
    setDistance(distance);
  }

  public String getName() {
    String sprint_name = String.format("%s meter sprint", Integer.toString(getDistance());
    return sprint_name;
  }

  public int getDistance() {
    return distance;
  }

  public void setDistance(int distance) {
    event_distance = distance;
  }
}

3 个答案:

答案 0 :(得分:6)

你的构造函数中有副作用,这是不赞成的。为获得最佳效果,请将副作用放在其他方法中。你已经有了这个,所以只需在javadoc中指定在构造之后应该调用greeting()(或者,它可以由子类构造函数调用,但是子子类会有同样的问题)。

答案 1 :(得分:1)

我假设每个种族都有距离,所以为什么不把这个字段作为超类型的一部分。然后可以通过提供给构造函数的参数来设置该字段。

Class Race {
  private int event_distance;
  public Race(Venue event_venue, int distance) {
    this.distance = distance;
    greeting();
  }

  public void greeting() {
    String event_greeting = String.format("The next event is: %s", getName());
    System.out.println(event_greeting);
  }

  public String getName() {
    return getClass().getSimpleName();
  }

  public int getDistance() {
    return distance;
  }

  public void setDistance(int distance) {
    event_distance = distance;
  }
}

提供distance作为超级构造函数的参数:

Class Sprint extends Race {
  private int event_distance;

  public Child(Venue event_venue, int distance) {
    super(event_venue, distance);
  }
  /* omitted rest of class */
}

答案 2 :(得分:0)

是的,这不起作用。

您需要以能够以正确顺序执行构造函数的方式重构代码。如果构造函数没有副作用并且不调用可以在子类中重写的方法(两者都是不鼓励的模式),通常这不是问题。

public Race(Venue event_venue) {
  greeting();   // constructor should not call non-final method
}

// method called by a constructor should not print anything
public void greeting() {
   String event_greeting = String.format("The next event is: %s", getName());
   System.out.println(event_greeting);
}