如何执行静态初始化块?

时间:2014-04-07 14:58:17

标签: java

搜索我的静态初始化块不会执行的原因的解释,我发现类中的静态初始化器永远不会执行if it references a final

所以我尝试通过删除MYWS_PROPS中的'final'来解决这个问题:

public class HibernateUtil {
  public static String MYWS_PROPS = "/myws.properties";

    private static final Logger LOG = Logger.getLogger(HibernateUtil.class.getName());
    private static final SessionFactory sessionFactory = buildSessionFactory();
    private static Properties sProps;

    static {
        try {
            sProps = new Properties();
            sProps.load(ServiceUtils.class.getResourceAsStream(MYWS_PROPS));
            LOG.info("Loaded (from " + MYWS_PROPS + ") connection url: " + sProps.getProperty("dburl"));
        } 
        catch (IOException e) {
            LOG.severe("Cannot find properties file " + MYWS_PROPS);
        }               
    }   



    private static SessionFactory buildSessionFactory() {
        try {
            Configuration config = new Configuration();
            config = config.configure("resources/hibernate.cfg.xml");
            config.setProperty("hibernate.connection.url", sProps.getProperty("dburl"));    // <== NullPointerException!        
            SessionFactory session = config.buildSessionFactory();
            return session;
        }
        catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

}

但是静态阻止仍然无法执行!

保证执行静态块的正确方法是什么?


更新:下面的所有答案都提到了引用该类的要求,以便运行静态初始化。所以我再次查看我的堆栈跟踪并验证该类确实被引用(否则,为什么它会在同一个类方法中引发异常?)

Caused by: java.lang.ExceptionInInitializerError
        at com.corp.dept.proj.myws.HibernateUtil.buildSessionFactory(HibernateUtil.java:76)
        at com.corp.dept.proj.myws.HibernateUtil.<clinit>(HibernateUtil.java:38)
        at com.corp.dept.proj.myws.ServicePortImpl.<init>(ServicePortImpl.java:82)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:126)
        ... 70 more
Caused by: java.lang.NullPointerException
        at com.corp.dept.proj.myws.HibernateUtil.buildSessionFactory(HibernateUtil.java:67)
        ... 77 more

但为了安全起见,我尝试了 Class.forName 建议:

Class.forName("com.corp.dept.proj.myws.HibernateUtil");
mProps.load(ServiceUtils.class.getResourceAsStream(HibernateUtil.MYWS_PROPS));

静态阻止仍无法执行。

所以我试着明确地实例化它:

HibernateUtil justExecTheDarnStaticBlock = new HibernateUtil();
mProps.load(ServiceUtils.class.getResourceAsStream(HibernateUtil.MYWS_PROPS));

但是静态阻止仍然无法执行!

我在这里缺少什么?

6 个答案:

答案 0 :(得分:3)

在处理静态初始化时,有意义

采用以下示例:

public class StaticTest {
    private static final String someString = initSomeString();
    private static final String someOtherString = initSomeOtherString();
    private static final String whoops;

    static {
        System.out.println("static initializer");
        whoops = "whoops";
    }

    public static void main(String[] args) {
        System.out.println(someOtherString);
    }

    private static String initSomeString() {
        System.out.println("initSomeString");
        return "Initialised";
    }

    private static String initSomeOtherString() {
        System.out.println("initSomeOtherString");
        return whoops + "y daisy";
    }
}

运行此类的结果如下:

initSomeString
initSomeOtherString
static initialiser
nully daisy

静态初始化按照声明的顺序发生,这意味着initSomeOtherString()在之前被称为,初始化whoops的静态初始化块。因此,此时whoops仍为null,因此生成的Stringnully daisy而不是whoopsy daisy

如果我重新安排课程,以便在静态初始化之后初始化someOtherString ,我得到了我想要的内容:

public class StaticTest {
    private static final String someString = initSomeString();
    private static final String whoops;

    static {
        System.out.println("static initialiser");
        whoops = "whoops";
    }

    private static final String someOtherString = initSomeOtherString();

    public static void main(String[] args) {
        System.out.println(someOtherString);
    }

    private static String initSomeString() {
        System.out.println("initSomeString");
        return "Initialised";
    }

    private static String initSomeOtherString() {
        System.out.println("initSomeOtherString");
        return whoops + "y daisy";
    }
}

打印

initSomeString
static initialiser
initSomeOtherString
whoopsy daisy

这是您遇到并导致问题的行为。您通过调用sessionFactory来初始化buildSessionFactory()sProps依赖config.setProperty("hibernate.connection.url", sProps.getProperty("dburl") ^ This hasn't been initialised yet 进行初始化:

sessionFactory

解决方案? 将{{1}}的声明移至以下静态初始化程序段。

答案 1 :(得分:2)

第一次引用类时将执行静态块。 (实例化或对静态成员的引用)

答案 2 :(得分:1)

如果你创建了一个类的实例,静态块肯定会执行。

编辑:评论中找到的实际解决方案如下:

buildSessionFactory()方法用于初始化sessionFactory。这取决于已经调用的静态块,但事实并非如此。如果您在静态块中而不是在其声明中调用sessionFactory = buildSessionFactory();,并且在sProps初始化之后问题将消失。

答案 3 :(得分:1)

您链接的问题只是讨论编译时常量;引用它们不会加载该类。但是你要加载类的任何事情 - 例如Class.forName("HibernateUtil") - 都必须运行静态初始化器。

此外,由于您正在处理的static变量不是原始类型或String,因此它无论如何都不能成为编译时常量。

答案 4 :(得分:0)

ClassLoader需要在静态块执行之前加载类。第一次引用类时会发生这种情况。

您可以使用Class.forName("");强制执行此操作。有了这个,您可以使用final变量

答案 5 :(得分:0)

如果您使用该课程,例如调用它的静态方法,创建它的实例,静态块将被执行。

另一种方法是通过调用Class.forName来明确地加载类。当您只知道名称(作为字符串)时,这非常有用。有时您必须扫描jar文件以获取名称并使用Class.forname加载它。