Как создать класс singleton
Каков наилучший/правильный способ создания класса singleton в java?
Одна из реализованных мной реализаций - это использование частного конструктора и метода getInstance().
package singleton;
public class Singleton {
private static Singleton me;
private Singleton() {
}
public static Singleton getInstance() {
if (me == null) {
me = new Singleton();
}
return me;
}
}
Но выполнение не выполняется в следующем тестовом случае
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<Singleton> 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");
}
}
}
Как разрешить это?
Спасибо
Ответы
Ответ 1
В соответствии с комментарием по вашему вопросу:
У меня есть файл свойств, содержащий несколько пар значений ключей, которые нужны всем приложениям, поэтому я думал об одном классе. Этот класс загрузит свойства из файла и сохранит его, и вы сможете использовать его из любой точки приложения
Не используйте синглтон. Вам, по-видимому, не нужна единовременная ленивая инициализация (это то, где синглтон - все). Вы хотите одноразовую прямую инициализацию. Просто сделайте его статическим и загрузите его в статический инициализатор.
например.
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);
}
// ...
}
Ответ 2
Если вы используете отражение для инкапсуляции, вы не должны удивляться, когда поведение вашего класса изменяется некорректным образом. Частные члены должны быть частными в классе. Используя отражение для доступа к ним, вы намеренно нарушаете поведение класса, и ожидаемый "дублирующий синглтон" ожидается.
Вкратце: не делайте этого.
Кроме того, вы можете подумать о создании экземпляра singleton в статическом конструкторе. Статические конструкторы синхронизированы и будут выполняться только один раз. Ваш текущий класс содержит условие гонки - если два отдельных потока вызывают getInstance()
, когда он еще не был вызван, существует вероятность того, что будут созданы два экземпляра, причем один из них является эксклюзивным для одного из потоков, а другой становясь экземпляром, который вызовет будущие вызовы getInstance()
.
Ответ 3
Я реализую синглтон ниже.
Из Singleton_pattern, описанный wikiepdia, используя Инициализация по требованию владельца
Это решение является потокобезопасным, не требуя специальных языковых конструкций (т.е. volatile
или 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;
}
}
Ответ 4
Я думаю, вы можете проверить, существует ли экземпляр уже в конструкторе и существует ли существует исключение
if(me != null){
throw new InstanceAlreadyExistsException();
}
Ответ 5
Лучший способ создания Singleton Class в java - использование Enums.
Пример, как показано ниже:
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();
}
}
Вызывается NoSuchMethodException, потому что мы не можем создать другой экземпляр enum 'SingleInstance' через его частный конструктор с использованием Reflection.
В случае сериализации enum реализует сериализуемый интерфейс по умолчанию.
Ответ 6
просто следуйте диаграмме классов шаблонов singleton,
SingletonClass
- singletonObject: SingletonClass
- SingletonClass()
+ getObject(): SingletonClass
Ключевая точка,
- частный ваш конструктор
- экземпляр вашего класса должен находиться внутри класса
- предоставить функцию для возврата вашего экземпляра
Некоторые коды,
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.
}
}