Java基础知识的澄清?

class test { test() { System.out.println("Constructor"); } { System.out.println("Hai"); } } public class sample { public static void main(String [] a) { test t = new test(); } } 

在上面的代码中,为什么在执行构造函数之前,在大括号((即)“Hai”)中给出的语句是Printed。

让我们用更清晰的例子来表达:

 public class Test { static { System.out.println("static initializer"); } { System.out.println("instance initializer"); } public Test() { System.out.println("constructor"); } } 

并测试如下:

 public class Main { public static void main(String[] args) { Test test1 = new Test(); Test test2 = new Test(); } } 

输出:

 static initializer instance initializer constructor instance initializer constructor 

静态初始值设定项仅在运行时执行一次 ,特别是在加载类时。 实例初始值设定项在构造函数之前的每个实例化期间执行。

您可以拥有多个,并且它们将按照它们在编码中出现的顺序执行。

实例初始化程序的主要好处是无论您使用哪种构造函数,它们都会被执行。 它们适用于每一个,因此您无需在所有这些上复制常见的初始化。

静态初始化程序的主要好处是它们在类加载期间只执行一次。 一个众所周知的现实世界的例子是JDBC驱动程序。 当你这样做

  Class.forName("com.example.jdbc.Driver"); 

只执行static初始化程序,然后任何(正常的)JDBC驱动程序将在DriverManager注册自己,如下所示

  static { DriverManager.registerDriver(new com.example.jdbc.Driver()); } 

这样, DriverManager可以在getConnection()期间找到正确的JDBC驱动程序。

是。 这是一个实例初始化器 。 一旦实例化它就会运行它。

在上面的代码中,为什么在执行构造函数之前,在大括号((即)“Hai”)中给出的语句是Printed。

因为这是预期的行为,如第12.5节“ Java语言规范 的新类实例的创建”中所述:)

在作为结果返回对新创建的对象的引用之前,处理指示的构造函数以使用以下过程初始化新对象:

  1. 将构造函数的参数分配给此构造函数调用的新创建的参数变量。
  2. 如果此构造函数以同一个类中的另一个构造函数的显式构造函数调用开始(使用this ),则使用这五个相同的步骤计算参数并以递归方式处理该构造函数调用。 如果该构造函数调用突然完成,则此过程突然完成,原因相同; 否则,继续步骤5。
  3. 此构造函数不是以同一个类中的另一个构造函数的显式构造函数调用开始的(使用this )。 如果此构造函数用于Object以外的类,则此构造函数将以超类构造函数的显式或隐式调用开始(使用super )。 使用这五个相同的步骤评估参数并递归处理超类构造函数调用。 如果该构造函数调用突然完成,则由于同样的原因,此过程突然完成。 否则,继续执行步骤4。
  4. 为此类执行实例初始值设定项和实例变量初始值设定 ,将实例变量初始值设定项的值按从左到右的顺序分配给相应的实例变量,在这些顺序中,它们以文本方式显示在类的源代码中。 如果执行任何这些初始值设定项导致exception,则不会处理其他初始值设定项,并且此过程会突然完成同样的exception。 否则,继续执行步骤5.(在某些早期实现中,如果字段初始值设定项表达式是一个常量表达式,其值等于其类型的默认初始化值,则编译器会错误地省略代码以初始化字段。)
  5. 执行此构造函数的其余部分。 如果该执行突然完成,则由于同样的原因,此过程突然完成。 否则,此过程正常完成。

有关…实例初始值设定项的更多详细信息,请参见8.6实例初始值设定项。

类中的大括号引入了一个实例初始化器(在Java 1.1中引入)。 它们的处理方式与分配作为声明一部分的字段的代码大致相同。 所以以下是等价的:

  private final Thing x = new Thing(); 

  private final Thing x; { x = new Thing(); } 

调用超级构造函数后,代码由构造函数立即执行。 因此,假设没有其他初始化,代码可以作为构造函数的一部分等效地编写:

  private final Thing x; public MyCLass() { super(); // Often implicit. x = new Thing(); } 

在相同位置的大括号前面有static关键字和静态初始化程序,在初始化类时执行一次,而不是基于每个实例。