Закрытая статическая переменная свойства приводит к исключению нулевого указателя

Я установил частный статический объект свойств для загрузки в некоторой конфигурации для моего фабричного класса в конструкторе фабричного класса.

public class BussinessServiceFactory {
    private static final BussinessServiceFactory factory = new BussinessServiceFactory();
    public static BussinessServiceFactory createBussinessServiceFactory(){
        return factory;
    }
    private BussinessServiceFactory(){
        InputStream in = BussinessServiceFactory.class.getClassLoader().getResourceAsStream("factory/bussinessservice.properties");
        try {
            bsConfig.load(in);
        } catch (IOException exception) {
            // TODO Auto-generated catch block
            throw new RuntimeException(exception);
        }
    }
    private static Properties bsConfig = new Properties();
    public <T> T createBussinessService(Class<T> clazz){
        try {
            String clazzName = clazz.getSimpleName();
            String name = bsConfig.getProperty(clazzName);
            return (T) Class.forName(name).newInstance();
        } catch (InstantiationException | IllegalAccessException
                | ClassNotFoundException exception) {
            throw new RuntimeException(exception);
        }
    }
}

Однако, когда я инициализирую класс, он бросает NullPointerException,

java.lang.NullPointerException
    at factory.BussinessServiceFactory.<init>(BussinessServiceFactory.java:15)
    at factory.BussinessServiceFactory.<clinit>(BussinessServiceFactory.java:8)
    ... 24 more

Затем, если я изменю свойства объекта на нестатический объект, проблема решена. Но меня все еще смущает причина, по которой это может произойти, и как это можно решить таким образом.

1 ответ

Решение

Статические инициализаторы выполняются сверху вниз. Так что статическое поле factory инициализируется, когда класс BussinessServiceFactory загружен. Этот статический инициализатор вызывает конструктор для BussinessServiceFactory и поэтому, в конце концов, загружает ссылку на статическое поле bsConfig, Это поле еще не инициализировано на данный момент, так как мы все еще находимся в статическом блоке инициализатора для factory поле. Следовательно, исключение NullPointerException.

Исправьте это либо 1) переупорядочение bsConfig поле должно быть выше factory поле, или, что еще лучше, не имеют этой зависимости между полями, делая bsConfig поле поле экземпляра (что вы и сделали, чтобы исправить это, и я считаю, что это лучший способ решить такую ​​проблему).

см. http://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html для получения подробной информации о порядке статической инициализации.

Приложение: трассировка стека раскрывает источник вашей проблемы. clinit в stacktrace обозначает cl ass init, и, следовательно, вы можете сказать, что проблема заключается в загрузке класса.

Другие вопросы по тегам