【问题标题】:How does the flow of object creation work in Java?Java 中的对象创建流程是如何工作的?
【发布时间】:2025-12-05 23:40:01
【问题描述】:

这里是 Java 和 OOP 的新手。

我试图了解何时可以使用对象的成员。具体来说,为什么在类中调用实例变量时不能将实例变量传递给构造函数?示例代码如下:

public class Point {

    public String name;

    {
        name = "Henry";
    }

    public Point()
    {
        this(this.name); // cannot reference this before supertype constructor has been called
    }

    public Point(String name)
    {
        this.name = name;
    }

}

以前有人问过这样的问题,但我不知道如何向 Google 询问我在此解释的内容。我知道我不能在 this(this.name) 调用中引用 this.name,因为尚未创建对象引用,但 Java 究竟是如何调用构造函数的?

构造函数将被执行的唯一时间是使用new Point()创建对象时,此时对象引用可用,并且编译器将没有任何东西可以执行抱怨。如果可以将this.name 分配给一个变量,然后将其传递给this(variable),它会起作用吗?有什么巨大的区别?我在这里完全误解了一些东西。

这就是我想象的方式,这显然是不正确的:

Point myPoint = new Point();

myPoint.name 现在等于 "Henry"

Point() 构造函数中,执行this(this.name) // which should be "Henry"

【问题讨论】:

  • 无聊的细节应该主要在docs.oracle.com/javase/specs/jls/se8/html/jls-12.html (在你的情况下,如果超类已经声明了该字段并且想要在它的构造函数中设置它会发生什么?这大致就是为什么 super 必须运行在你可以使用任何东西之前)
  • 当您执行new Point() 时,就像new 是一个返回对刚刚在堆上构造的Point 对象的引用的方法(在引擎盖下只是一点内存包含所有实例变量/引用/...dzone.com/articles/java-object-memory)。它不会首先创建Object。直接是Point。但是PointObject(通过继承),所以Object 构造函数会找到它所知道的期望。因此,当您extend时,您不能带走。

标签: java oop constructor


【解决方案1】:

我不知道这是否完全回答了你的问题,因为它有点令人困惑,但我会尽力而为:

为了创建一个新对象,您可以使用new 操作数,例如Point point = new Point();。 您的对象可以/应该包含属性,并且您在创建 public String name; 时就开始了它(尽管您应该对此进行搜索,因为它们不应该是公开的)。如果您必须为属性分配默认值,则必须在其声明后立即执行(例如public String name = "Henry";。同样,您可能需要搜索 java 常量来解决此问题。

这段代码可以帮助你理解(我认为)你想要做什么:

public class Point {

    public String name = "Henry";

    public Point() {

    }

    public Point(String name) {
        this.name = name; //changes current value (Henry) to the one sent as an argument.
    }


    public static void main(String[] args) {
        Point pointA = new Point();
        Point pointB = new Point("Other name");

        System.out.println(pointA.name);
        System.out.println(pointB.name);
    }
}

在这段代码中,您可以找到一个空对象 (new Point();) 和一个名为“其他名称”的实例 (new Point("Other name");)。

如果你运行它,你可以看到两个实例之间的差异。

希望对您有所帮助!

编辑: 附言您可能还想搜索有关 getter/setter 的信息。

【讨论】:

【解决方案2】:

构造函数将被执行的唯一时间是使用 new Point() 创建对象时,到那时对象引用将可用,编译器不会有任何东西抱怨。

我想说这里的关键点是对象引用只有在构造函数被调用之后才可用。因此,在构造函数的操作过程中 引用 this 并没有真正的意义。

还请记住,通过继承,您可以在实例化/创建特定对象之前调用多个构造函数。例如:

public class ParentPoint {
    public String name = "Parent Point";

    public ParentPoint() {
        // do something
    }
}

public class Point extends ParentPoint {

    public Point() {
        super();
        // do something else
    }

}

在这种情况下,您将在 Point 完全实例化之前调用两个构造函数(因此您在 OP 中提到的流程并不总是那么简单)。

Xavier Silva 的答案代码很好,同时拥有 getter 和 setter 也很理想:

public class Point {

    public String name = "Henry";

    public Point() {

    }

    public Point(String name) {
        this.name = name; //changes current value (Henry) to the one sent as an argument.
    }

    public void setName(String newName) {
        this.name = newName;
    }

    public String getName() {
        return this.name;
    }


    public static void main(String[] args) {
        Point pointA = new Point();
        Point pointB = new Point("Other name");

        System.out.println(pointA.name); // Henry
        System.out.println(pointB.name); // Other name

        pointA.setName("New name");
        System.out.println(pointA.getName()); // New name
    }
}

最后一段演示了getter和setter,其余代码未修改。

【讨论】:

  • 谢谢,我多读了一些,明白了对象只有在构造函数执行后才被初始化。我不能在this() 中引用this.name,因为这样做会在执行超类构造函数之前尝试操作引用。我还发现构造函数只能链接到另一个构造函数。所以this(this.name) 被用来代替super() 期望Point(String name)(这是this() 所指向的)来执行它,但被告知在任何构造函数执行super() 之前处理this.name。我说的对吗?
  • 抱歉耽搁了 - 我有点不确定您评论的某些方面,但是是的,您所说的总体上似乎是正确的。
【解决方案3】:

您可以通过清空 this(this.name) 构造函数来实现您的目标 - 这样,调用一个空构造函数 - new Point() - 将 name 保留为 Henry,并使用另一个构造函数 - 例如new Point("Bob") - 将该名称 ("Bob") 设置为名称。

我相信您也可以通过将第一个“this”替换为“super”来做到这一点。

【讨论】: