java构造函数顺序

发布于 2024-12-08 19:11:28 字数 1795 浏览 0 评论 0原文

这个java程序很简单,注释也很多,所以你很快就能理解它。但是,为什么在构造staff[1]时,程序首先转到语句:

this("Employee #" + nextId, s);

然后转到对象初始化块,然后再回到语句,多么混乱。为什么不首先使用对象初始化块

import java.util.*;

public class ConstructorTest
{
   public static void main(String[] args)
   {
      // fill the staff array with three Employee objects
      Employee[] staff = new Employee[3];

      staff[0] = new Employee("Harry", 40000);
      staff[1] = new Employee(60000);
      staff[2] = new Employee();

      // print out information about all Employee objects
      for (Employee e : staff)
         System.out.println("name=" + e.getName()
            + ",id=" + e.getId()
            + ",salary=" + e.getSalary());
   }
}

class Employee
{
   // three overloaded constructors
   public Employee(String n, double s)
   {
      name = n;
      salary = s;
   }

   public Employee(double s)
   {
      // calls the Employee(String, double) constructor
      this("Employee #" + nextId, s);
   }

   // the default constructor
   public Employee()
   {
      // name initialized to ""--see below
      // salary not explicitly set--initialized to 0
      // id initialized in initialization block
   }

   public String getName()
   {
      return name;
   }

   public double getSalary()
   {
      return salary;
   }

   public int getId()
   {
      return id;
   }

   private static int nextId;

   private int id;
   private String name = ""; // instance field initialization
   private double salary;

   // static initialization block
   static
   {
      Random generator = new Random();
      // set nextId to a random number between 0 and 9999
      nextId = generator.nextInt(10000);
   }

   // object initialization block
   {
      id = nextId;
      nextId++;
   }
}

This java program is easy and full of comment,so you can understand it fast.however,why in construct staff[1],the program first go to the statement:

this("Employee #" + nextId, s);

then go to the object initialization block,and then go back to the statement,how confusion.why not it first use the object initialization block

import java.util.*;

public class ConstructorTest
{
   public static void main(String[] args)
   {
      // fill the staff array with three Employee objects
      Employee[] staff = new Employee[3];

      staff[0] = new Employee("Harry", 40000);
      staff[1] = new Employee(60000);
      staff[2] = new Employee();

      // print out information about all Employee objects
      for (Employee e : staff)
         System.out.println("name=" + e.getName()
            + ",id=" + e.getId()
            + ",salary=" + e.getSalary());
   }
}

class Employee
{
   // three overloaded constructors
   public Employee(String n, double s)
   {
      name = n;
      salary = s;
   }

   public Employee(double s)
   {
      // calls the Employee(String, double) constructor
      this("Employee #" + nextId, s);
   }

   // the default constructor
   public Employee()
   {
      // name initialized to ""--see below
      // salary not explicitly set--initialized to 0
      // id initialized in initialization block
   }

   public String getName()
   {
      return name;
   }

   public double getSalary()
   {
      return salary;
   }

   public int getId()
   {
      return id;
   }

   private static int nextId;

   private int id;
   private String name = ""; // instance field initialization
   private double salary;

   // static initialization block
   static
   {
      Random generator = new Random();
      // set nextId to a random number between 0 and 9999
      nextId = generator.nextInt(10000);
   }

   // object initialization block
   {
      id = nextId;
      nextId++;
   }
}

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

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

发布评论

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

评论(4

池予 2024-12-15 19:11:28

因为 this("Employee #" + nextId, s); 包含对超类构造函数的隐式调用,当然必须在子类的初始化块之前执行。

使用实例初始化器通常是一个坏主意,因为它们并不为人所知,除了构造函数之外不能做任何事情,并且混合两者会导致混乱。

Because this("Employee #" + nextId, s); includes an implicit call to the superclass constructor, which of course must be executed before the initializer block of the subclass.

Using instance initializers is generally a bad idea as they are not well known, cannot do anything more than constructors, and mixing both leads to confusion.

讽刺将军 2024-12-15 19:11:28

这遵循 JLS 的 8.8.7.1 节中指定的顺序:(

最后两颗子弹)

设 C 为正在实例化的类,S 为 C 的直接超类,i 为正在创建的实例。显式构造函数调用的评估过程如下:

  • 首先,如果构造函数调用语句是超类构造函数调用,
    (被剪掉了,因为这不是我们的情况)
  • 接下来,调用构造函数。
  • 最后,如果构造函数调用语句是超类构造函数调用,并且构造函数调用语句正常完成,则执行 C 的所有实例变量初始值设定项和 C 的所有实例初始值设定项。 (截图)备用构造函数调用不会执行此附加隐式操作。

因此,实例初始值设定项在调用超级构造函数后立即执行 - 这是(隐式)来自public Employee(String n, double s)。这应该在执行该两参数构造函数的主体之前发生。

This follows the order specified in section 8.8.7.1 of the JLS:

(Final two bullets)

Let C be the class being instantiated, let S be the direct superclass of C, and let i be the instance being created. The evaluation of an explicit constructor invocation proceeds as follows:

  • First, if the constructor invocation statement is a superclass constructor invocation,
    (Snipped because it's not in our case)
  • Next, the constructor is invoked.
  • Finally, if the constructor invocation statement is a superclass constructor invocation and the constructor invocation statement completes normally, then all instance variable initializers of C and all instance initializers of C are executed. (Snip) An alternate constructor invocation does not perform this additional implicit action.

So the instance initializer is executed immediately after the superconstructor is called - which is (implicitly) from public Employee(String n, double s). This should happen before the body of that two-parameter constructor is executed.

心如狂蝶 2024-12-15 19:11:28

不确定实际问题是什么,有点令人困惑。初始化(静态、对象、构造函数)的顺序是预定义的,与它们在代码中出现的顺序无关。至于一般风格,我通常不鼓励使用对象初始化块。这是一个非常常见的错误源,它使异常处理更加复杂并且难以调试。此外,这不是一种非常常见的模式,因此开发人员在分析错误时往往会错过寻找它。

Not sure what the actual question is, it's a bit confusing. The order of initialization (static, object, constructor) is predefined and has nothing to do with in which order they appear in the code. As for the general style, I generally discourage using object initialization blocks. It's a very common source of errors, it makes exception-handling more complex and it's hard to debug. In addition, it's not a very common pattern so developers tend to miss looking for it when analyzing bugs.

土豪我们做朋友吧 2024-12-15 19:11:28

Java 编译器必须确保从每个构造函数中调用对象初始化块中的代码。对于大多数构造函数,它通过在隐式或显式调用 super() 之后将代码插入到构造函数中来实现此目的。然而,对于以 this() 开头的编译器,首先,没有super() 的隐式调用——其他构造函数处理那。其次,在这样的构造函数中,根本无法插入对象初始值设定项块,因为在调用第二个构造函数时将拾取代码。因此,this() 调用是首先发生的事情。

The Java compiler must ensure that the code in the object initialization block is called from each constructor. For most constructors, it does this by inserting the code into the constructor right after the implicit or explicit call to super(). For compilers that start with this(), however, first of all there is no implicit call to super() -- the other constructor handles that. Secondly, in such a constructor the object initializer block can't be inserted at all, since the code will be picked up when the second constructor is called. Therefore the this() call is the very first thing that happens.

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