0

有人可以指出我的误解吗?

我有两个类,一个 Abstract 和一个 Concrete,如下所示:

public abstract class Abstract
{
    protected static int ORDER = 1;

    public static void main (String[] args)
    {
        Concrete c = new Concrete("Hello");
    }

    public Abstract()
    {
        Class c = this.getClass();
        System.out.println(ORDER++ + ": Class = " 
            + c.getSimpleName() 
            + "; Abstract's no-arg constructor called.");
    }

    public Abstract(String arg)
    {
        this();
        Class c = this.getClass();
        System.out.println(ORDER++ + ": Class = " 
            + c.getSimpleName() 
            + "; Abstract's 1-arg constructor called.");
    }
}

public class Concrete extends Abstract
{
   public Concrete()
   {
      super();
      Class c = this.getClass();
      System.out.println(ORDER++ + ": Class = " 
          + c.getSimpleName() 
          + "; Concrete's no-arg constructor called.");
   }

   public Concrete(String arg)
   {
      super(arg);
      Class c = this.getClass();
      System.out.println(ORDER++ + ": Class = " 
          + c.getSimpleName() 
          + "; Concrete's 1-arg constructor called.");
   }
}

当我运行它时,我得到以下输出:

1)类=混凝土;Abstract 的无参数构造函数被调用。
2)类=混凝土;Abstract 的 1-arg 构造函数被调用。
3)类=混凝土;调用了具体的 1-arg 构造函数。

我的问题是:为什么从 Abstract 的 String arg 构造函数对 this() 的调用不调用 Concrete 上的这个无参数构造函数?或者,也许更相关的是,有什么方法可以让 Abstract 的 String arg 构造函数调用 Concrete 上的无参数构造函数,从而允许构造函数的“正确”链接?

4

5 回答 5

7

否 - 构造函数链接总是横向(在同一类型中)或向上(到父类型)。

不要忘记调用必须在编译时解决- 并且Abstract不知道将从它派生哪些其他类,或者他们将拥有哪些构造函数。

可以在构造函数中调用虚拟方法Abstract,并在 ... 中覆盖该方法,Concrete但我敦促您要这样做。特别是,构造函数体 forConcrete尚未执行,变量初始化器也不会执行 - 因此它无法对Concrete特定状态执行任何操作。在某些非常特殊的情况下,这是正确的做法,但它们很少见,应谨慎处理。

你到底想做什么?通常我发现最好有许多“横向”链通向一个具有“向上”链的构造函数。

于 2009-12-07T11:55:18.043 回答
1

您应该知道子类始终对父类隐藏。您不能像在子类中那样直接调用子类的方法或构造函数。

于 2013-04-30T12:00:31.287 回答
1

这是一篇专注于抽象类的需求及其工作原理的帖子。希望这会对您有所帮助。

于 2011-08-25T05:58:18.027 回答
1

就是这样(由 Jon Skeet 详细介绍)。

您可以向 Concrete 添加一个 init 块:

{
  Class c = this.getClass();
  System.out.println(ORDER++ + ": Class = " 
  + c.getSimpleName() 
   + "; Concrete's init block called.");
}

与默认构造函数相比,总是调用初始化程序块:

1: Class = Concrete; Abstract's no-arg constructor called.
2: Class = Concrete; Abstract's 1-arg constructor called.
3: Class = Concrete; Concrete's init block called.
4: Class = Concrete; Concrete's 1-arg constructor called.
于 2009-12-07T11:59:11.453 回答
0

处理这个问题的最好方法通常是让一个类的所有构造函数最终使用一个通用构造函数,即:

public Abstract() {
  this(null);
}
public Abstract(String arg) {
  // do all Abstract init here
}

public Concrete() {
  this(null);
}
public Concrete(String arg) {
  super(arg);
  // do all Concrete init here
}
于 2009-12-07T15:37:50.520 回答