Costruttore in una classe di metodi statici
-
27-10-2019 - |
Domanda
Ho una classe di metodi statici che possono essere eseguiti su una mappa tenuta all'interno della classe e voglio che la mappa venga impostata quando viene chiamata la classe. Ho provato a usare un convolgente privato, ma non viene chiamato. Le parti pertinenti del mio codice sono:
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
}
Un costruttore privato è la cosa giusta da usare qui, e in tal caso cosa sto facendo di sbagliato?
Scusa se questo è un duplicato; Ho provato a cercare risposte, ma non sono sicuro di cosa cercare!
Soluzione
Il blocco iniziale statico è stato menzionato in diverse altre risposte. Ma praticamente trovo il seguente linguaggio più frequentemente in natura:
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;
}
}
Altri suggerimenti
No, un costruttore privato non è quello che vuoi. Un costruttore inizializza un esempio della tua classe (quando chiami new MyClass()
), ma lo stato statico non appartiene a un'istanza e quindi non dovrebbe essere inizializzato dal costruttore. Inizializzazione che si desidera accadere quando la classe viene caricata per la prima volta dovrebbe essere in a static
blocco posizionato a livello di classe.
static {
populateMyMap();
}
Ma non dovresti mai usare lo stato statico (globale). Lo stato statico rende il tuo sistema proibitivamente difficile da testare, è più sfumato dello stato di istanza (ad esempio, hai una copia per carico della classe) ed è in genere più difficile rendere il thread sicuro.
Considera di rendere la tua mappa un Membro dell'istanza della tua classe invece.
Usa l'inizializzatore statico:
public class MyClass
{
static {
//init
}
}
Esistono due modi per raggiungere questo obiettivo. Uno è quello di rendere il metodo "PopulatemyMap" un inizializzatore statico (o l'approccio suggerito da AH). Quindi è garantito per essere eseguito prima della prima chiamata statica. Questo di solito è il modo migliore, supponendo che il costo di eseguire PopulatemyMap sia abbastanza piccolo da non essere notato, o se si utilizza la funzionalità della classe quasi ogni volta che l'applicazione viene eseguita.
L'approccio alternativo è ciò che useresti se eseguire "populatemymap" è qualcosa che richiede un tempo significativo e o potresti non usare la funzionalità per alcune esecuzioni dell'app o si desidera differire l'esecuzione di PopulatemyMap fino ai dati è necessario, per non aumentare inutilmente il tempo di avvio.
Se il secondo approccio è quello che desideri, dovresti cambiare le strutture e utilizzare un singleton piuttosto che metodi statici. Rendi i metodi (e i dati) non statici e fai sì che ogni utente ottenga l'istanza Singleton prima di chiamare il metodo su di esso. Avere "populatemymap" chiamato nel costruttore (privato). Sì, lo so, i singleton hanno una cattiva reputazione e la gente dice sempre "evitali perché sono solo metodi globali sotto mentite spoglie", ma i metodi statici sono anche solo metodi globali. Non stai perdendo nulla. E in questo modo non si paga il costo dell'esecuzione di PopulatemyMap fino a quando (o a meno che) non sia necessario.
ATTENZIONE: se le tue strutture di dati non sono immutabili, cioè possono essere cambiate dopo che sono state inizializzate, probabilmente non dovresti usare nessuna di queste strutture.