java - tipos - Constructor en una clase de métodos estáticos
que es un destructor en java (4)
Tengo una clase de métodos estáticos que se pueden realizar en un mapa dentro de la clase, y quiero que el mapa se configure cuando se llame a la clase. He intentado usar un contructor privado, pero no se está llamando. Las partes relevantes de mi código son:
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
}
Es un constructor privado lo que se debe usar aquí, y si es así, ¿qué estoy haciendo mal?
Perdón si es un duplicado; Intenté buscar respuestas, ¡pero no estoy seguro de qué buscar!
El bloque de inicializador estático se ha mencionado en varias otras respuestas. Pero prácticamente encuentro el siguiente modismo con más frecuencia en la naturaleza:
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;
}
}
Hay dos formas de lograr esto. Una es hacer que el método "populateMyMap" sea un inicializador estático (o el enfoque sugerido por AH). Entonces se garantiza que se ejecutará antes de la primera llamada estática. Esta es generalmente la mejor manera, suponiendo que el costo de ejecutar populateMyMap es lo suficientemente pequeño como para no ser notado, o si vas a utilizar la funcionalidad de la clase casi cada vez que se ejecuta la aplicación.
El enfoque alternativo es lo que usaría si ejecutar "populateMyMap" es algo que lleva una cantidad de tiempo significativa Y o bien puede que no use la funcionalidad para algunas ejecuciones de la aplicación, o si desea diferir la ejecución de populateMyMap hasta que los datos es necesario, para no aumentar innecesariamente el tiempo de inicio.
Si el segundo enfoque es lo que quiere, entonces debe cambiar las estructuras y utilizar un Singleton en lugar de métodos estáticos. Haga que los métodos (y datos) no sean estáticos y haga que cada usuario obtenga la instancia de Singleton antes de llamar al método. Haga que se llame "populateMyMap" en el constructor (privado). Sí, lo sé, los Singleton tienen una mala reputación y la gente siempre dice "evítenlos porque son solo métodos globales disfrazados", pero los métodos estáticos también son solo métodos globales. No estás perdiendo nada. Y de esta forma no paga el costo de ejecutar populateMyMap hasta (o a menos) que lo necesite.
ADVERTENCIA: si sus estructuras de datos no son inmutables, es decir, pueden cambiarse después de que se hayan inicializado, entonces probablemente no deba utilizar ninguna de estas estructuras.
No, un constructor privado no es lo que quieres. Un constructor inicializa una instancia de su clase (cuando llama a una new MyClass()
), pero el estado estático no pertenece a una instancia y, por lo tanto, no debe inicializarse desde el constructor. La inicialización que desea que suceda cuando la clase se carga por primera vez debe estar en un bloque static
ubicado en el nivel de clase.
static {
populateMyMap();
}
Pero nunca deberías estar usando un estado estático (global). El estado estático hace que su sistema sea prohibitivamente difícil de probar, tiene más matices que el estado de la instancia (por ejemplo, tiene una copia por carga de la clase) y por lo general es más difícil proteger el hilo.
Considere hacer que su mapa sea un miembro de instancia de su clase.
Use el inicializador estático:
public class MyClass
{
static {
//init
}
}