Come creare una class singleton

Qual è il modo migliore / corretto per creare una class singleton in java?

Una delle implementazioni che ho trovato sta usando un costruttore privato e un metodo getInstance ().

package singleton; public class Singleton { private static Singleton me; private Singleton() { } public static Singleton getInstance() { if (me == null) { me = new Singleton(); } return me; } } 

Ma l’implementazione fallisce nel seguente caso di test

 package singleton; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class Test { /** * @param args * @throws NoSuchMethodException * @throws SecurityException * @throws InvocationTargetException * @throws IllegalAccessException * @throws InstantiationException * @throws IllegalArgumentException */ public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { Singleton singleton1 = Singleton.getInstance(); System.out.println(singleton1); Singleton singleton2 = Singleton.getInstance(); System.out.println(singleton2); Constructor c = Singleton.class .getDeclaredConstructor((Class[]) null); c.setAccessible(true); System.out.println(c); Singleton singleton3 = c.newInstance((Object[]) null); System.out.println(singleton3); if(singleton1 == singleton2){ System.out.println("Variable 1 and 2 referes same instance"); }else{ System.out.println("Variable 1 and 2 referes different instances"); } if(singleton1 == singleton3){ System.out.println("Variable 1 and 3 referes same instance"); }else{ System.out.println("Variable 1 and 3 referes different instances"); } } } 

Come risolvere questo?

Grazie

Come da commento alla tua domanda:

Ho un file delle proprietà contenente alcune coppie di valori delle chiavi, che è necessario attraverso l’applicazione, ecco perché stavo pensando a una class singleton. Questa class caricherà le proprietà da un file e la manterrà e potrai utilizzarla da qualsiasi punto dell’applicazione

Non usare un singleton. Apparentemente non hai bisogno di inizializzazione pigra una tantum (è qui che si trova un singleton). Si desidera l’ inizializzazione diretta una tantum. Basta renderlo statico e caricarlo in un inizializzatore statico.

Per esempio

 public class Config { private static final Properties PROPERTIES = new Properties(); static { try { PROPERTIES.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties")); } catch (IOException e) { throw new ExceptionInInitializerError("Loading config file failed.", e); } } public static String getProperty(String key) { return PROPERTIES.getProperty(key); } // ... } 

Se si utilizza la riflessione per perforare l’incapsulamento, non si dovrebbe essere sorpresi quando il comportamento della class viene alterato in modi errati. I membri privati ​​dovrebbero essere privati ​​della class. Utilizzando la reflection per accedervi, si intende interrompere intenzionalmente il comportamento della class e il risultante “duplicato singleton” è previsto.

In breve: non farlo.

Inoltre, potresti prendere in considerazione la creazione dell’istanza Singleton in un costruttore statico. I costruttori statici sono sincronizzati e verranno eseguiti una sola volta. La tua class corrente contiene una condizione di competizione – se due thread separati chiamano getInstance() quando non è stato chiamato in precedenza, esiste la possibilità che vengano create due istanze, una delle quali è esclusiva di uno dei thread e l’altra diventando l’istanza che le future chiamate getInstance() restituiranno.

Implementerò singleton in basso.

Da Singleton_pattern descritto da wikiepdia usando l’idioma del titolare di Initialization-on-demand

Questa soluzione è thread-safe senza richiedere costrutti di linguaggio speciali (cioè volatile o synchronized

 public final class LazySingleton { private LazySingleton() {} public static LazySingleton getInstance() { return LazyHolder.INSTANCE; } private static class LazyHolder { private static final LazySingleton INSTANCE = new LazySingleton(); } private Object readResolve() { return LazyHolder.INSTANCE; } } 

Il modo migliore per creare Singleton Class in java è usare Enums.

Esempio come di seguito:

 import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; enum SingleInstance{ INSTANCE; private SingleInstance() { System.out.println("constructor"); } } public class EnumSingletonDemo { public static void main (String args[]) throws FileNotFoundException, IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { SingleInstance s=SingleInstance.INSTANCE; SingleInstance s1=SingleInstance.INSTANCE; System.out.println(s.hashCode() + " "+s1.hashCode());//prints same hashcode indicates only one instance created //------- Serialization ------- ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("sample.ser")); oos.writeObject(s); oos.close(); //------- De-Serialization ------- ObjectInputStream ois=new ObjectInputStream(new FileInputStream("sample.ser")); SingleInstance s2=(SingleInstance) ois.readObject(); System.out.println("Serialization :: "+s.hashCode()+" "+s2.hashCode());// prints same hashcodes because JVM handles serialization in case of enum(we dont need to override readResolve() method) //-----Accessing private enum constructor using Reflection----- Class c=Class.forName("SingleInstance"); Constructor co=c.getDeclaredConstructor();//throws NoSuchMethodException co.setAccessible(true); SingleInstance newInst=(SingleInstance) co.newInstance(); } } 

Viene generata NoSuchMethodException perché non possiamo creare un’altra istanza di enum ‘SingleInstance’ tramite il suo costruttore privato utilizzando Reflection.

In caso di serializzazione, enum implementa l’interfaccia serializzabile per impostazione predefinita.

Penso che sia ansible verificare se un’istanza esiste già nel costruttore e se esiste un’eccezione

 if(me != null){ throw new InstanceAlreadyExistsException(); } 

basta seguire il diagramma delle classi del modello singleton,

SingletonClass – singletonObject: SingletonClass – SingletonClass () + getObject (): SingletonClass

Punto chiave,

  • privato il tuo costruttore
  • l’istanza della tua class dovrebbe essere all’interno della class
  • fornire la funzione per restituire l’istanza

Qualche codice,

 public class SingletonClass { private static boolean hasObject = false; private static SingletonClass singletonObject = null; public static SingletonClass getObject() { if (hasObject) { return singletonObject; } else { hasObject = true; singletonObject = new SingletonClass(); return singletonObject; } } private SingletonClass() { // Initialize your object. } }