Конструктор в классе статических методов

У меня есть класс статических методов, которые можно выполнять на карте, хранящейся в классе, и я хочу, чтобы карта настраивалась при вызове класса. Я пытался использовать частного конструктора, но он не вызывается. Соответствующие части моего кода:

public class MyClass
{
    private static final String KEYS = "ABC";
    private static final String[] DATA = {"AAA", "BBB", "CCC"};
    private static HashMap<Character, String> myMap;

    private MyClass() {
        System.out.println("Running constructor");
        populateMyMap();
    }

    private static void populateMyMap() {
        myMap = new HashMap<Character, String>();
        for (int i=0; i < KEYS.length; i++) {
            myMap.put(KEYS.charAt(i), DATA[i]);
        }
    }

    //various static methods
}

Правильно ли здесь использовать частный конструктор, и если да, то что я делаю неправильно?

Извините, если это дубликат; Я пробовал искать ответы, но я не уверен, что искать!


person DenverCoder8    schedule 12.01.2012    source источник


Ответы (4)


Блок статического инициализатора упоминался в нескольких других ответах. Но на практике я чаще встречаю в дикой природе следующую идиому:

public class MyClass
{
    private static HashMap<Character, String> myMap = createMyMap();

    private static HashMap<Character, String> createMyMap() {
        HashMap<Character, String> myTmpMap = new HashMap<Character, String>();
        for (int i=0; i < KEYS.length; i++) {
            myTmpMap.put(KEYS.charAt(i), DATA[i]);
        }
        return myTmpMap;
    }
}
person A.H.    schedule 12.01.2012
comment
Да, если это просто инициализация значения, это намного предпочтительнее. - person Mark Peters; 12.01.2012

Нет, частный конструктор - это не то, что вам нужно. Конструктор инициализирует экземпляр вашего класса (при вызове new MyClass()), но статическое состояние не принадлежит экземпляру и поэтому не должно инициализироваться из конструктора. Инициализация, которую вы хотите выполнить при первой загрузке класса, должна быть в блоке static, размещенном на уровне класса.

static {
   populateMyMap();
}

Но вы никогда не должны использовать статическое (глобальное) состояние. Статическое состояние делает вашу систему непомерно сложной для тестирования, оно более тонкое, чем состояние экземпляра (например, у вас есть одна копия на загрузку класса), и, как правило, сложнее сделать потокобезопасным.

Попробуйте вместо этого сделать свою карту экземпляром вашего класса.

person Mark Peters    schedule 12.01.2012
comment
Это также потребует переписать все статические методы как методы экземпляра, что, на мой взгляд, хорошо. - person emory; 12.01.2012

Используйте статический инициализатор:

public class MyClass
{
    static {
    //init
    }
}
person Christian Kuetbach    schedule 12.01.2012

Есть два способа добиться этого. Один из них - сделать метод "populateMyMap" статическим инициализатором (или подход, предложенный А.Х.). Тогда он гарантированно будет выполнен до первого статического вызова. Обычно это лучший способ, если предположить, что либо стоимость запуска populateMyMap достаточно мала, чтобы ее не заметили, либо если вы собираетесь использовать функциональные возможности класса почти каждый раз при запуске приложения.

Альтернативный подход — это то, что вы могли бы использовать, если выполнение «populateMyMap» требует значительного времени, И либо вы можете не использовать функциональность для некоторых исполнений приложения, либо вы хотите отложить выполнение populateMyMap до тех пор, пока не будут получены данные. нужен, чтобы без необходимости не увеличивать время запуска.

Если вам нужен второй подход, вам следует переключать структуры и использовать Singleton, а не статические методы. Сделайте методы (и данные) нестатическими и попросите каждого пользователя получить экземпляр Singleton перед вызовом для него метода. Вызовите «populateMyMap» в (частном) конструкторе. Да, я знаю, у синглтонов плохая репутация, и люди всегда говорят: «Избегайте их, потому что это просто замаскированные глобальные методы», но статические методы также являются просто глобальными методами. Вы ничего не теряете. Таким образом, вы не платите за выполнение populateMyMap до тех пор, пока (или пока) вам это не понадобится.

ПРЕДУПРЕЖДЕНИЕ. Если ваши структуры данных не являются неизменяемыми, т. е. их можно изменить после инициализации, то вам, вероятно, не следует использовать какие-либо из этих структур.

person DJClayworth    schedule 12.01.2012