【问题标题】:What is the advantage of using initialization blocks? [duplicate]使用初始化块有什么好处? [复制]
【发布时间】:2012-01-18 02:48:15
【问题描述】:

我知道初始化块在类首次加载(静态初始化块)或创建实例时(实例初始化块)运行。

class SmallInit {
   static int x;
   int y;
   static { x = 7 ; } // static init block
   { y = 8; } // instance init block
}

但是,当我们可以这样做时,这样做有什么特别的好处:

class SmallInit {
   static int x = 7;
   int y = 8;
}

【问题讨论】:

标签: java initialization


【解决方案1】:

没有什么特别的好处,它可以在某些情况下提高可读性(通常是在声明多个成员时)。

【讨论】:

    【解决方案2】:

    我没有看到仅包含单行变量声明的静态块有任何特殊好处。事实上,当您所做的只是为类或实例变量赋值时,(在我看来)更难理解发生了什么。

    但是,当您需要构建更复杂的起始状态时,静态块和实例块确实会派上用场。这是一个同时使用声明和静态块的示例:

    static List<Sprocket> mySprockets = new ArrayList<Sprocket>();
    
    static {
        mySprockets.add(new Sprocket("foo", 17));
        mySprockets.add(new Sprocket("bar", 8));
    }
    

    【讨论】:

      【解决方案3】:

      以下可能是实例初始化块的优势:

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

      转到here 以获得良好的概览。

      【讨论】:

        【解决方案4】:

        我过去曾使用初始化块来填充复杂的数据结构。但是,我开始觉得编写一个填充数据结构并调用它的静态函数是一种更好的方法。

        例如

        private static Map foo = initFoo();
        
        private static Map initFoo() {
          Map foo = new Map();
          foo.put("x", "y");
          foo.put("a", "b");
          return foo;
        }
        

        例如,有些人不熟悉初始化程序块,如果您决定希望在其他上下文中使用您的初始化代码,那么您可以轻松地调用该函数。

        【讨论】:

          【解决方案5】:

          实例初始化块的一个好处是它们使Double Brace Initialization 模式成为可能。

          而不是这个:

          Set<String> names = new HashSet<String>();
          names.add("Peter");
          names.add("Paul");
          names.add("Mary");
          

          你可以这样做:

          Set<String> names = new HashSet<String>() {{
              add("Peter");
              add("Paul");
              add("Mary");
          }};
          

          第一个大括号创建一个匿名内部类;第二个启动实例初始化程序块。 (请注意,这意味着namesHashSet 的匿名子类 的实例,但这通常不是问题。这也意味着这种模式仅适用于非最终类。)

          这在一次性将对象初始化为表达式很方便的情况下特别有用。例如:

          doSomethingToSet(new HashSet<String>() {{
              add("Peter");
              add("Paul");
              add("Mary");
          }});
          

          【讨论】:

          • 小心这个 - 它绝对有效,但它创建了一个内部类,它隐式引用了“this”。如果您没有预料到,这可能会导致一些有趣的 GC 行为……我并不是说不要使用它(我当然会这样做),但请注意。
          • @KevinDay 你能详细说明一下吗?我对可能出现的潜在问题感兴趣。
          • 当然——如果你像这样初始化一个地图,它最终会隐式引用外部对象。如果您随后将该映射传递到应用程序的另一个区域,则“外部对象”将不会被释放,直到映射本身也被释放。如果地图纯粹是对象的实现,那么这很好。但是,如果您在外部接口中公开地图,则会向您打开这样的意外引用。
          【解决方案6】:
          1. 没有初始化器,变量将被初始化 为 0 或 null。因此,如果您要在 构造函数到其他值,你实际上设置了两次(一次 为 0 或 null,然后在构造函数中再次设置为你想要的)。这 在绝大多数情况下,性能损失可以忽略不计(一个 异常可能是您在紧密循环中使用的数学类,但是 即使这将非常依赖于该循环中发生的其他情况)。
          2. 它有助于提高可读性。
          3. 如果从构造函数调用虚方法,则派生的数据成员 被覆盖的虚方法中使用的类将具有 0 或 null 作为值 除非它有初始化程序。我不是 100% 在 Java 中就是这种情况 已经有一段时间了;我知道它是用 C# 编写的。

          【讨论】:

            猜你喜欢
            • 2012-10-02
            • 2016-05-30
            • 2015-02-24
            • 2017-09-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2014-03-16
            相关资源
            最近更新 更多