【问题标题】:Clarification in Java basics?Java基础知识的澄清?
【发布时间】:2010-12-25 23:35:05
【问题描述】:
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”)中给出的语句。

【问题讨论】:

    标签: java


    【解决方案1】:

    让我们用一个更清楚的例子来表达:

    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 驱动程序。

    【讨论】:

      【解决方案2】:

      是的。这是一个instance initializer。它在类被实例化后立即运行。

      【讨论】:

      • 那么静态关键字是可选的吗?
      • 那么如果在上面的代码中创建一个静态块,它会先运行静态块还是静态初始化块?......你能解释一下什么是静态初始化器吗?
      • 绝对不是 static 初始化器。
      • 哎呀,你是对的,它根本不是静态的,它是一个实例初始化器。固定。
      • 因为有很多人不理解它和/或因为一个拥有 10K+ 代表的“必须”是正确的。
      【解决方案3】:

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

      因为这是Java Language Specification12.5 Creation of New Class Instances 部分所述的预期行为:)

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

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

      请参阅8.6 Instance Initializers 部分以了解有关...实例初始化程序的更多详细信息。

      【讨论】:

        【解决方案4】:

        类中的大括号直接引入了实例初始化器(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 关键字和静态初始化器之前的相同位置的大括号,在初始化类时执行一次,而不是在每个实例的基础上。

        【讨论】:

          猜你喜欢
          • 2011-06-01
          • 2014-06-19
          • 2013-03-23
          • 1970-01-01
          • 1970-01-01
          • 2020-07-19
          • 1970-01-01
          • 2014-04-16
          • 2018-05-25
          相关资源
          最近更新 更多