【问题标题】:Use of static init block使用静态初始化块
【发布时间】:2011-01-12 12:50:06
【问题描述】:

我知道静态初始化块是如何工作的。
谁能告诉我它的一些典型用途。

【问题讨论】:

    标签: java static-initializer


    【解决方案1】:

    尽量避免使用静态初始化块。相反,您可以使用私有静态初始化函数,这将使您的代码更干净。

    我会参考@Bozho的例子。

    不要做

    public static Configuration configuration;
    static {
         confuguration = new Configuration();
         configuration.setSomething(..);
         configuration.setSomethingElse(..);
         ...
    }
    

    改为使用

    public static Configuration configuration = createConfiguration();
    

    public static Configuration configuration = YourConfiguration.create();
    

    【讨论】:

    • 同意。使用上述块会导致单元测试出现严重问题。
    【解决方案2】:

    当你想在一个地方初始化一个或多个静态变量时

    这很有用,因为您可以应用异常处理,而这是内联初始化无法实现的。

    例如:

    public static ImageIcon defaultIcon = ImageIO.read(..);
    

    可以用

    初始化
    public static ImageIcon defaultIcon;
    static {
       try {
           defaultIcon = ImageIO.read(..);
       } catch (IOException ex){
         System.out.println("No default icon available");
       }
    }
    

    另一个应用是复杂的初始化。例如,如果一个项目需要多行代码来初始化。假设您有一个配置:

    public static Configuration configuration;
    static {
         confuguration = new Configuration();
         configuration.setSomething(..);
         configuration.setSomethingElse(..);
         ...
    }
    

    第三种用法是初始化一些外部 API 基础设施。我当前项目的一个例子:

    static {
        org.apache.xml.security.Init.init();
    }
    

    但是,正如 Mykola Golubyev 所说,静态初始化块会降低代码的可读性,因此请谨慎使用。静态方法更透明地做同样的事情。

    【讨论】:

    【解决方案3】:
    • 初始化集合静态 字段,例如 Map、List、Set 等
    • 初始化同样是静态的基于 setter 的对象

    【讨论】:

      【解决方案4】:

      它们通常与JNI 代码结合使用,以确保加载所需的本机库:

      class MyJniConnection {
      
          public static native void myJniCall();
      
          static {
              System.load("native.dll");
          }
      }
      

      【讨论】:

        【解决方案5】:

        它们可用于创建 DSL,就像 JMock 所做的那样。例如,设置用户将被保存到数据库的期望:

        Mockery context = new Mockery();
        final Database database = context.mock(Database.class);    
        ...
        context.checking(new Expectations() {{
            oneOf(database).save(user);
        }});
        
        // Rest of the test
        

        【讨论】:

          【解决方案6】:

          JDBC 驱动是一个流行的例子

          为什么需要Class.forName() 将驱动程序加载到内存中。答案很简单。在 JDBC 规范中规定,所有 JDBC Driver 都有一个静态块,以便在加载 Driver 类后立即向 DriverManager 注册自己。像这样的:

          static {
              try {
                  java.sql.DriverManager.registerDriver(new Driver());
              } catch (SQLException E) {
                  throw new RuntimeException("Can't register driver!");
              }
          }
          

          所以,当你编写时(例如这里的 MySQL 驱动程序):

          Class.forName("org.gjt.mm.mysql.Driver");
          

          类加载器尝试加载和链接org.gjt.mm.mysql.Driver 类,如果成功,静态初始化块将被执行,Driver 将自己注册到DriverManager

          【讨论】:

            【解决方案7】:
            • 静态块:-当我们想在加载类的时候执行代码,那么我们可以把代码放在静态块中......
            • init :- 当我们想在类的对象初始化时执行代码时,我们可以将代码放在 init 块中......

            【讨论】:

              猜你喜欢
              • 2011-01-26
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-09-12
              • 1970-01-01
              相关资源
              最近更新 更多