Ответ 1
Попробуйте создать свой публичный конструктор
private Singleton() {
if( Singleton.singleton != null ) {
throw new InstantiationError( "Creating of this object is not allowed." );
}
}
Я знаю, что в Java мы можем создать экземпляр класса new
, clone()
, Reflection
и serializing and de-serializing
.
Я создал простой класс, реализующий Singleton.
И мне нужно полностью остановить экземпляр моего класса.
public class Singleton implements Serializable{
private static final long serialVersionUID = 3119105548371608200L;
private static final Singleton singleton = new Singleton();
private Singleton() { }
public static Singleton getInstance(){
return singleton;
}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("Cloning of this class is not allowed");
}
protected Object readResolve() {
return singleton;
}
//-----> This is my implementation to stop it but Its not working. :(
public Object newInstance() throws InstantiationException {
throw new InstantiationError( "Creating of this object is not allowed." );
}
}
В этом классе мне удалось остановить экземпляр класса new
, clone()
и serialization
, но я не смог остановить его с помощью Reflection.
Мой код для создания объекта
try {
Class<Singleton> singletonClass = (Class<Singleton>) Class.forName("test.singleton.Singleton");
Singleton singletonReflection = singletonClass.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
Попробуйте создать свой публичный конструктор
private Singleton() {
if( Singleton.singleton != null ) {
throw new InstantiationError( "Creating of this object is not allowed." );
}
}
Определите синглтон следующим образом:
public enum Singleton {
INSTANCE
}
Как насчет проверки в конструкторе:
private Singleton() {
if (singleton != null) {
throw new IllegalStateException("Singleton already constructed");
}
}
Конечно, это может не остановить его - если кто-то возится с рефлексией, чтобы получить доступ к закрытым членам, они могут установить поле для нулевого значения. Вы должны спросить себя, что именно вы пытаетесь предотвратить, и как это стоит.
(EDIT: Как сказал Божо, окончательные поля могут быть недоступны даже при отражении. Я не удивлюсь, если есть какой-то способ сделать это через JNI и т.д., хотя... если вы дадите людям достаточно доступа, я смогу сделать почти что угодно...)
private Singleton() {
if (Singleton.singleton != null) {
throw new RuntimeException("Can't instantiate singleton twice");
}
}
Еще одна вещь, которую вы должны посмотреть - это метод readResolve(..)
, потому что ваш класс реализует Serialiable
. Там вы должны вернуть существующий экземпляр.
Но самый простой способ использования синглонов - перечислить - вы не беспокоитесь об этом.
В качестве альтернативы синглтону вы можете взглянуть на шаблон monostate. Затем создание экземпляра вашего класса больше не является проблемой, и вам не нужно беспокоиться о любом из перечисленных вами сценариев.
В шаблоне monostate все поля в вашем классе static
. Это означает, что все экземпляры класса имеют одно и то же состояние, как с одним синглоном. Более того, этот факт прозрачен для вызывающих; им не нужно знать о специальных методах, таких как getInstance
, они просто создают экземпляры и работают с ними.
Но, как и в случае с singleton, это форма скрытого глобального состояния; что очень плохо.
I Thing Ниже код будет работать.
class Test {
static private Test t = null;
static {
t = new Test();
}
private Test(){}
public static Test getT() {
return t;
}
public String helloMethod() {
return "Singleton Design Pattern";
}
}
public class MethodMain {
public static void main(String[] args) {
Test t = Test.getT();
System.out.println(t.helloMethod());
}
}
: Шаблон проектирования Singleton
Мы можем разбить его, используя статический вложенный класс
Пожалуйста, следуйте приведенному ниже коду, его 100% правильно, я протестировал
package com.singleton.breakable;
import java.io.Serializable;
class SingletonImpl implements Cloneable, Serializable {
public static SingletonImpl singleInstance = null;
private SingletonImpl() {
}
@Override
protected Object clone() throws CloneNotSupportedException {
return singleInstance;
};
public Object readResolve() {
return SingletonImpl.getInstance(); //
}
public static SingletonImpl getInstance() {
if (null == singleInstance) {
singleInstance = new SingletonImpl();
}
return singleInstance;
}
}
package com.singleton.breakable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
class FullySingletonClass {
public static void main(String[] args) {
SingletonImpl object1 = SingletonImpl.getInstance();
System.out.println("Object1:" + object1);
try {
FileOutputStream fos = new FileOutputStream("abc.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object1);
FileInputStream fis = new FileInputStream("abc.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
SingletonImpl object2 = (SingletonImpl) ois.readObject();
System.out.println("Object2" + object2);
} catch (Exception e) {
// TODO: handle exception
}
try {
Constructor[] constructors = SingletonImpl.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// Below code will not destroy the singleton pattern
constructor.setAccessible(true);
SingletonImpl Object3 = (SingletonImpl) constructor.newInstance();
System.out.println("Object3: Break through Reflection:" + Object3);
break;
}
} catch (Exception ew) {
}
}
}
**OUTPUT**
Object1:[email protected]
[email protected]
Object3: Break through Reflection:[email protected]
Просто отметим, что с Java 8 и, согласно моей проверке, вы не можете создать экземпляр Singleton через Reflections, если у него есть частный конструктор.
Вы получите это исключение:
Exception in thread "main" java.lang.IllegalAccessException: Class com.s.Main can not access a member of class com.s.SingletonInstance with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Unknown Source)
at java.lang.Class.newInstance(Unknown Source)
at com.s.Main.main(Main.java:6)
Here Reflection not work
package com.singleton.nonbreakable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Constructor;
class FullySingletonClass {
public static void main(String[] args) {
SingletonImpl object1 = SingletonImpl.getInstance();
System.out.println("Object1:" + object1);
try {
FileOutputStream fos = new FileOutputStream("abc.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(object1);
FileInputStream fis = new FileInputStream("abc.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
SingletonImpl object2 = (SingletonImpl) ois.readObject();
System.out.println("Object2" + object2);
} catch (Exception e) {
// TODO: handle exception
}
try {
Constructor[] constructors = SingletonImpl.class.getDeclaredConstructors();
for (Constructor constructor : constructors) {
// Below code will not destroy the singleton pattern
constructor.setAccessible(true);
SingletonImpl Object3 = (SingletonImpl) constructor.newInstance();
System.out.println("Object3:" + Object3);
break;
}
} catch (Exception ew) {
}
}
}
package com.singleton.nonbreakable;
import java.io.Serializable;
class SingletonImpl implements Cloneable, Serializable {
public static SingletonImpl singleInstance = null;
private static class SingletonHolder {
public static SingletonImpl getInstance() {
if (null == singleInstance) {
singleInstance = new SingletonImpl();
}
return singleInstance;
}
}
private SingletonImpl() {
}
@Override
protected Object clone() throws CloneNotSupportedException {
return singleInstance;
};
public Object readResolve() {
System.out.println("Executing readResolve again");
return SingletonImpl.getInstance(); // FIXME
}
public static SingletonImpl getInstance() {
return SingletonHolder.getInstance();
}
}
Output :
Object1:[email protected]
Executing readResolve again
[email protected]