Обратите внимание, что я прошел через следующую ветку:
Как эффективен способ реализации одноэлементного шаблона в Java?
Подводя итог, при написании синглтона необходимо учитывать следующие важные моменты:
- Доступ к нескольким потокам не должен приводить к нескольким экземплярам
- Синглтон, если он сериализуем, должен гарантировать, что десериализация не создаст новый экземпляр
- В случае атаки отражением должно быть выдано исключение / ошибка.
Теперь, как уже упоминалось в вышеупомянутой теме, использование перечисления для создания синглтона обеспечивает все 3 упомянутые выше точки
Ниже приведены примеры кодов, которые я написал
/*Singleton class using enum*/
package com.java.patterns;
public enum MemoryTasks {
INSTANCE;
public void performScheduleTasks(){
System.out.println("In performScheduleTasks().");
}
private MemoryTasks(){
System.out.println("In private constructor."+this.hashCode());
}
public int returnHashCodeOfInstance(){
return INSTANCE.hashCode();
}
}
/*Class to access private constructor of the Singleton*/
package com.java.reflection;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import com.java.patterns.MemoryTasks;
public class LaunchReflection {
public static void main(String[] args) {
launchRelectionAttack();
}
public static void launchRelectionAttack(){
Class vulnClass = null;
Constructor [] vulClassConstr = null;
Type [] vulClassConstrParamTypes = null;
try {
vulnClass = Class.forName("com.java.patterns.MemoryTasks");
vulClassConstr = vulnClass.getDeclaredConstructors();
for(Constructor constr : vulClassConstr){
vulClassConstrParamTypes = constr.getGenericParameterTypes();
System.out.println("Modifier private ? "+Modifier.isPrivate(constr.getModifiers()));
}
/*for(Type paramType : vulClassConstrParamTypes){
System.out.println(paramType.toString());
}*/
System.out.println(MemoryTasks.INSTANCE.returnHashCodeOfInstance());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
/*Class to write the enum to a file*/
package com.java.io.serialize;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import com.java.patterns.MemoryTasks;
public class ObjectWriter {
public static void main(String[] args) {
try {
writeSerObjectToFile();
} catch (IOException e) {
e.printStackTrace();
}
}
private static void writeSerObjectToFile() throws IOException {
File file = null;
FileOutputStream fos = null;
ObjectOutputStream oos = null;
file = new File("D:/Omkar/Dump/SerObj");
try{
if(!file.exists()){
file.createNewFile();
}
fos = new FileOutputStream(file);
oos = new ObjectOutputStream(fos);
oos.writeObject(MemoryTasks.INSTANCE);
}catch(IOException e){
e.printStackTrace();
}
finally{
oos.close();
fos.close();
}
}
}
/*Class to read the serialized enum from file*/
package com.java.io.serialize;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;
import com.java.patterns.MemoryTasks;
public class ObjectRead {
public static void main(String[] args) {
readSerObjFromFile();
}
private static void readSerObjFromFile() {
File file = null;
FileInputStream fis = null;
ObjectInputStream ois = null;
file = new File("D:/Omkar/Dump/SerObj");
try {
fis = new FileInputStream(file);
if(fis.available() > 0){
ois = new ObjectInputStream(fis);
MemoryTasks instance = (MemoryTasks) ois.readObject();
System.out.println("Reading from serialised file : "+instance.returnHashCodeOfInstance());
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
Я был бы рад, если бы мне объяснили, как обеспечиваются пункты 2 и 3!