Java:抽象类构造函数和 this()

发布于 2024-08-14 05:18:29 字数 1564 浏览 4 评论 0原文

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

我有两个类,一个抽象类和一个具体类,如下所示:

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)类别=混凝土; 调用 Concrete 的 1-arg 构造函数。

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

Can someone point out what I'm misunderstanding?

I've got two classes, an Abstract and a Concrete, as follows:

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.");
    }
}

and

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.");
   }
}

When I run this I get the following output:

1) Class = Concrete; Abstract's no-arg
constructor called.
2) Class =
Concrete; Abstract's 1-arg constructor
called.
3) Class = Concrete;
Concrete's 1-arg constructor called.

My question is this: why doesn't the call to this() from Abstract's String arg constructor call this no-arg constructor on Concrete? Or, perhaps more pertinently, is there any way to get Abstract's String arg constructor to call the no-arg constructor on Concrete, allowing a "proper" chaining of Constructors?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

终陌 2024-08-21 05:18:29

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

不要忘记调用必须在编译时解析 - 并且 Abstract 不知道其他类将从它派生什么,或者它们的构造函数是什么会有的。

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

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

No - constructor chaining always goes either sideways (in the same type) or upwards (to the parent type).

Don't forget that the call has to be resolved at compile-time - and Abstract doesn't know what other classes are going to derive from it, or what constructors they'll have.

You could call a virtual method within the Abstract constructor, and override that method within Concrete... but I would urge you not to do that. In particular, the constructor body for Concrete won't have been executed yet, and neither will the variable initializers - so it wouldn't be able to do anything with Concrete-specific state. There are some very specific situations where that's the correct thing to do, but they're rare and should be handled with caution.

What are you actually trying to do? Usually I find it's better to have many "sideways" chains leading to a single constructor which has the "upward" chain.

绿光 2024-08-21 05:18:29

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

That's simply the way it is (as detailed by Jon Skeet).

You could add an init block to Concrete though:

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

In contrast to the default constructor, the inizializer block is always 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.
孤檠 2024-08-21 05:18:29

这是帖子重点关注抽象类的需求及其工作原理。希望这会对您有所帮助。

Here is the post which focus on what the need of abstract class and how it works.May this will help you.

追星践月 2024-08-21 05:18:29

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

You should have to know that a child class is always hidden from the parent class. You can't call the method or constructor of child class directly like you did in child class.

不及他 2024-08-21 05:18:29

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

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
}

the best way to handle this is generally to have all constructors for a class end up using one common constructor, i.e.:

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
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文