2012-01-12 2 views
4

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

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 
} 

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

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

ответ

5

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

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; 
    } 
} 
+0

Да, если это просто инициализировать значение, это, безусловно, предпочтительнее. –

3

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

public class MyClass 
{ 
    static { 
    //init 
    } 
} 
8

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

static { 
    populateMyMap(); 
} 

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

Рассмотрите возможность сделать свою карту экземпляром экземпляра вашего класса.

+0

Для этого также потребуется переписать все статические методы как методы экземпляра, что, на мой взгляд, является хорошей вещью. – emory

0

Существует два способа достижения этой цели. Один из них заключается в том, чтобы сделать метод populateMyMap статическим инициализатором (или подходом, предложенным A.H.). Тогда гарантируется выполнение перед первым статическим вызовом. Обычно это лучший способ, предполагая, что либо стоимость запуска populateMyMap достаточно мала, чтобы не быть заметной, либо если вы собираетесь использовать функциональные возможности этого класса почти каждый раз, когда приложение запускается.

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

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

ВНИМАНИЕ: Если ваши структуры данных не являются неизменяемыми, то есть они могут быть изменены после их инициализации, то вы, вероятно, не должны использовать какую-либо из этих структур.