【问题标题】:Java: Abstract class constructors and this()Java:抽象类构造函数和 this()
【发布时间】:2009-12-07 11:53:15
【问题描述】:

有人能指出我的误解吗?

我有两个类,一个 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) 等级 = 混凝土;摘要的无参数 调用构造函数。
2)类= 具体的; Abstract 的 1-arg 构造函数 叫。
3)类=混凝土; 调用了具体的 1-arg 构造函数。

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

【问题讨论】:

    标签: java constructor this abstract


    【解决方案1】:

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

    不要忘记调用必须在编译时解决 - 而Abstract 不知道将从它派生出什么其他类,或者他们将使用什么构造函数有。

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

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

    【讨论】:

    • 谢谢乔恩。 getClass 知道 Object 是具体的,但是 this() 调用 Abstract no-arg 构造函数的事实对我来说似乎有点不自然。在我看来,我试图实现的链接似乎允许构造函数之间更自然地划分责任。我想我必须在 Concrete 的构造函数中复制代码,或者将其移到一个新方法中,但由于我没有编写这个 Abstract 类的所有具体实现,所以我必须为其他开发人员记录这些内容.
    • 所以您试图将构造函数视为虚拟方法?是的,那是行不通的。
    【解决方案2】:

    就是这样(由 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.
    

    【讨论】:

      【解决方案3】:

      这里是post,它专注于抽象类的需求以及它是如何工作的。希望这会对你有所帮助。

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

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

          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
          }
          

          【讨论】:

            猜你喜欢
            • 2015-03-20
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2022-12-04
            • 1970-01-01
            • 2015-10-25
            • 2023-03-04
            相关资源
            最近更新 更多