【问题标题】:How is an instance initializer different from a constructor?实例初始化器与构造器有何不同?
【发布时间】:2010-11-24 06:10:39
【问题描述】:

换句话说,为什么需要实例初始化器?与构造函数相比,编写实例初始化程序有什么不同或优势?

【问题讨论】:

  • 实例初始化器非常少见(除非您遇到热衷于双括号习语的人的代码)。

标签: java instantiation


【解决方案1】:

当您有许多构造函数并希望为每个构造函数执行一些公共代码时,您可以使用实例初始化程序。因为它被所有构造函数调用。

【讨论】:

    【解决方案2】:

    就对象生命周期而言,没有区别。两者都在构造时调用,逻辑上初始化块可以被认为是构造的一部分。

    从语义上讲,初始化器是一个不错的工具,原因如下:

    初始化器可以通过将初始化逻辑保留在正在初始化的变量旁边来提高代码的可读性:

       public class Universe {
           public int theAnswer;
           {
             int SIX = 6;
             int NINE = 7;
             theAnswer = SIX * NINE;
           }
    
           // a bunch of other vars
       }
    

       public class Universe {
           public int theAnswer;
    
           // a bunch of other vars
    
           public Universe() {
             int SIX = 6;
             int NINE = 7;
             theAnswer = SIX * NINE;
    
             // other constructor logic
           }
       }
    

    不管怎样,初始化器都会被调用 使用了哪个构造函数。

    初始化器可以匿名使用 内部类,其中构造函数 不能。

    【讨论】:

    • 从技术上讲,您拥有的是“实例变量初始化器”而不是“实例初始化器”(直接嵌套在类中的块)。请参阅 JLS 第 3 节第 8.6 节。
    • 实例初始化程序块没有如 here 所示的名称。不是吗?您已使用名称 theAnswer 标记了您的实例初始化程序代码。那是对的吗?或者我错过了什么。
    • @RBT theAnswer 是一个声明的实例变量。它在匿名初始化程序块中初始化。注意变量声明后的分号。
    【解决方案3】:

    这似乎解释得很好:

    实例初始化器是实例变量的有用替代品 任何时候的初始化器:

    • 初始化代码必须捕获异常,或者

    • 执行无法用实例变量初始化器表达的奇特计算。 当然,你总是可以在 构造函数。

    但是在一个有多个构造函数的类中,你必须在每个构造函数中重复代码。使用实例初始化器,您 可以只写一次代码,无论如何都会执行 构造函数用于创建对象。实例初始化器是 在匿名内部类中也很有用,它不能声明任何 构造函数。

    发件人:JavaWorld Object initialization in Java

    【讨论】:

    • 另一方面,您可以在一个构造函数中编写一次代码,然后从所有其他构造函数中调用它。但是匿名内部类是一个很好的观点。
    • 您可以从其他构造函数调用它 - 但随后您再次重复调用。如果您添加一个新的构造函数,您必须记住添加对它的调用。实例初始化器并非如此。
    • @talonx,我同意你关于遗忘的论点,但使用默认行为同样危险。当支持者阅读遗留代码中的构造函数时,人们不会总是记得检查可能的实例初始值设定项。而显式使用的 init() 会脱颖而出。
    • @javamonkey79: 你是说如果我为我的类选择 constructor 而不是 instance initializer ,那么实例初始化器唯一有用的地方是使用匿名类?
    • @Assambar 您不能在 init() 方法中分配最终字段,但可以在初始化程序块中。
    【解决方案4】:

    一般来说,我会避免使用实例初始化器惯用语——它相对于变量初始化器的唯一真正优势是异常处理。

    而且由于 init 方法(可从构造函数调用)也可以进行异常处理,也可以集中构造函数设置代码,但具有可以对构造函数参数值进行操作的优点,我会说实例初始化程序是多余的,并且因此要避免。

    【讨论】:

    • 您必须在所有构造函数中手动调用 init 方法。
    • @Alex 好点,但由于大多数具有多个构造函数的类具有共同的逻辑,因此它们倾向于相互调用。至少在我的大部分课程中。
    【解决方案5】:

    初始化程序是在构造函数之间共享代码的一种方式,如果初始化程序与变量声明一起使用,它会使代码更具可读性。

    Java 编译器将初始化程序块复制到每个构造函数中。因此,这种方法可用于在多个构造函数之间共享代码块。 Oracle documentation

    【讨论】:

      【解决方案6】:

      实例初始化器优于构造器的真正优势体现在我们使用匿名内部类时

      匿名内部类不能有构造函数(因为它们是匿名的) 所以它们非常适合实例初始化器

      【讨论】:

        【解决方案7】:

        在创建对象时,如果我们想初始化实例变量,那么我们应该去构造器,如果我们想在创建对象时执行任何活动,那么我们应该去实例块。

        我们不能用实例块替换构造器,因为构造器可以带参数,但实例块不能带参数。

        我们不能用构造函数替换实例块,因为一个类可以包含多个构造函数。如果我们想用构造函数替换实例块,那么在每个构造函数中我们都必须编写实例块代码,因为在运行时我们无法预料会调用哪个构造函数,这会不必要地增加重复代码。

        示例:

        class MyClass{
        
            static int object_count = 0;
        
            MyClass(){
                object_count++;
            }
        
            MyClass(int i){
        
                object_count++;
            }
        
            void getCount() {
        
                System.out.println(object_count);
            }
        
            public static void main(String... args) {
                MyClass one = new MyClass();
                MyClass two = new MyClass(2);
                two.getCount();
            }
        }
        

        输出: 2

        class MyClass{
        
            static int object_count = 0;
        
            {
                object_count++;
            }
        
            MyClass(){
        
            }
        
            MyClass(int i){     
        
            }
        
            void getCount() {
        
                System.out.println(object_count);
            }
        
            public static void main(String... args) {
                MyClass one = new MyClass();
                MyClass two = new MyClass(2);
                two.getCount();
            }
        }
        

        输出: 2

        【讨论】:

          猜你喜欢
          • 2014-03-22
          • 1970-01-01
          • 2015-05-01
          • 1970-01-01
          • 1970-01-01
          • 2010-10-22
          • 2011-03-10
          • 2018-06-30
          • 2013-11-17
          相关资源
          最近更新 更多