构造函数中的多态方法 (Java)

发布于 2025-01-01 17:22:14 字数 1061 浏览 0 评论 0原文

A在构造函数中调用公共方法f()。 B 类用它自己的实现重写方法f()

假设您实例化对象B..对象B的方法f()将在对象A的构造函数中调用>,尽管对象 B 尚未完全初始化。

谁能解释这种行为?

编辑:是的,不推荐这样做..但我不明白为什么Java没有调用f()< /code> 实现基类 A,而不是“延伸”到派生类 Bf() 实现。

代码:

class A {
    A() {
        System.out.println("A: constructor");
        f();
    }

    public void f() {
        System.out.println("A: f()");
    }
}

class B extends A {
    int x = 10;
    B() {
        System.out.println("B: constructor");
    }

    @Override
    public void f() {
        System.out.println("B: f()");
        this.x++;
        System.out.println("B: x = " + x);

    }
}

public class PolyMethodConst {
    public static void main(String[] args) {
        new B();
    }
}

输出:

A: constructor
B: f()
B: x = 1
B: constructor

Class A calls the public method f() in the Constructor. Class B overrides method f() with its own implementation.

Suppose you intantiate Object B.. method f() of Object B would be called in the Constructor of Object A, although Object B is not fully initialized.

Can anyone explain this behavior?

EDIT: Yes, it's not recommended practice.. yet i don't understand why Java is not calling the f() implementation of the base-Class A instead of "reaching out" to the f() implementation of the derived Class B.

Code:

class A {
    A() {
        System.out.println("A: constructor");
        f();
    }

    public void f() {
        System.out.println("A: f()");
    }
}

class B extends A {
    int x = 10;
    B() {
        System.out.println("B: constructor");
    }

    @Override
    public void f() {
        System.out.println("B: f()");
        this.x++;
        System.out.println("B: x = " + x);

    }
}

public class PolyMethodConst {
    public static void main(String[] args) {
        new B();
    }
}

Output:

A: constructor
B: f()
B: x = 1
B: constructor

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

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

发布评论

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

评论(4

箹锭⒈辈孓 2025-01-08 17:22:14

你是对的,这就是它的工作原理。不过,不建议这样做,因为从您的类继承的人可能会无意中破坏它。

You're correct, that is the way it works. It's not recommended practice though, because somebody who inherits from your class can unintentionally break it.

此岸叶落 2025-01-08 17:22:14

每当创建子类的实例时,都会首先调用超类构造函数(隐式 super())。因此它打印出

a: constructor

f() is invoked next,并且由于子类重写了超类方法,因此调用了子类f()。所以你会看到

B: f()

现在,子类还没有初始化(super()仍在执行),所以x默认值为0,因为是 int 类型的默认值。因为您递增了它 (this.x++;),所以它变为 1

B: x = 1

现在,超类构造函数已完成并在子类构造函数处恢复,因此

B: constructor

实例变量现在设置为您指定的值(与对应于类型的默认值(0 表示数字,false 表示 booleannull代码>供参考))

注意:如果您现在在新创建的对象上打印 x 的值,它将是 10

因为这是一个不好的做法,静态如果您尝试执行此操作,代码分析工具(PMD、FINdBugs 等)会向您发出警告。

Whenever you create an instance of the subclass, the super classes constructor is invoked first (implicit super()). So it prints

a: constructor

f() is invoked next and since subclass overrides the superclass method, the subclass f() is invoked. So you will see

B: f()

Now, the subclass is not initialized yet (still super() is executing) so x default's to the value 0 because that is the default value for type int. Because you incremented it (this.x++;) it becomes 1

B: x = 1

Now, the superclass constructor is complete and resumes at the subclasses constructor and hence

B: constructor

The instance variables are now set to the values you have specified (against the default values that correspondt to the type (0 for numerics, false for boolean and null for references))

NOTE: If you now print the value of x on the newly created object, it will be 10

Since this is a bad practice, the static code analysis tools (PMD, FIndBugs etc) warn you if you try to do this.

当爱已成负担 2025-01-08 17:22:14

我只会提供一个链接,因为我对这个主题不太了解。请参阅此处了解有关构造函数调用顺序的教程。

该页面末尾与您所描述的情况相关的最突出的引述如下:

  1. 调用基类构造函数。递归地重复此步骤,以便首先构建层次结构的根,
    接下来是下一个派生类,依此类推,直到最后一个派生类
    已达到。
  2. 成员初始值设定项按声明顺序调用。调用派生类构造函数的主体。

因此,正如您在示例中所示,基类被初始化,然后以下每个类被初始化,最后成员变量被初始化。

但正如比尔所提到的,这不是一个好的做法。遵循比尔所说的。他的名气比我大。

编辑:有关更完整的答案,请参阅此 Jon Skeet 答案。此答案中的链接已损坏,并且据我所知只能找到 JLS 的 pdf 副本这里是 .pdf 格式的 JLS 副本格式。相关章节为第 8.8.7.1 节。该答案中有关于构造函数调用顺序的解释。

I'll just provide a link, since I'm not very well-informed on the subject. See here for a tutorial that talks about the invocation order of constructors.

The most prominent quote at the end of the page related to the situation you describe is the following:

  1. The base-class constructor is called. This step is repeated recursively such that the root of the hierarchy is constructed first,
    followed by the next-derived class, etc., until the most-derived class
    is reached.
  2. Member initializers are called in the order of declaration. The body of the derived-class constructor is called.

So, as you've shown in your example, the base-class is initialised, then each of the following classes is instatiated and finally the member variables are initialised.

But as Bill as mentioned, this is not a good practice. Follow what Bill says. He has more rep than me.

EDIT: For a more complete answer, see this Jon Skeet answer. The link in this answer is broken, and only a pdf copy of the JLS can be found AFAIK. Here is a copy of the JLS in .pdf format. The relevant section is Section 8.8.7.1. There is an explanation of what the constructor invocation order is in that answer.

两个我 2025-01-08 17:22:14

new B()时,A的构造函数被隐式调用或通过super()调用。虽然它是在 A 类中定义的,但实际上当前的类是 B。

尝试将以下调试信息添加到 A 的构造函数和函数中。

System.out.println(this.getClass());

在您的情况下,A类中的函数f()已被B类覆盖,因此A()中的函数将调用B()的实现。然而,如果f()是私有方法并且不能被B覆盖,则Af()将以更高的优先级被调用。

但正如其他人评论的那样,这不是一个好的做法。

When new B(), A's Constructor is called implicitly or called via super(). Although it is defined in Class A, actually the current class is B.

Try add the below debug info into A's constructor and functions.

System.out.println(this.getClass());

In your case, the function f() in Class A has been overriden by Class B, so the function in A() will call B()'s implementation. However, if the f() is a private method and can not be override by B, the A.f() will be called with higher priorities.

But as others commented, it's not a good practice.

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