Apart the enum solution, all the others can be workaround-ed via Reflexion
These are two examples on how to workaround the Dave G Solution :
1 : Setting the variable Singleton.singleton to null
Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
Constructor theConstructor = constructors[0];
theConstructor.setAccessible(true);
Singleton instance1 = (Singleton) theConstructor.newInstance();
Singleton.getInstance();
Field f1 = Singleton.class.getDeclaredField("singleton");
f1.setAccessible(true);
f1.set(f1, null);
Singleton instance2 = (Singleton) theConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
Output :
- Singleton@17f6480
- Singleton@2d6e8792
2 : not calling the getInstance
Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
Constructor theConstructor = constructors[0];
theConstructor.setAccessible(true);
Singleton instance1 = (Singleton) theConstructor.newInstance();
Singleton instance2 = (Singleton) theConstructor.newInstance();
System.out.println(instance1);
System.out.println(instance2);
Output :
- Singleton@17f6480
- Singleton@2d6e8792
So I can think of 2 ways if you don't want to go with an Enum :
1st option : Using the securityManager :
It prevent from using unauthorized operations (calling private methods from outside the class ....)
So you just need to add one line to the singleton constructor proposed by the other answers
private Singleton() {
if (singleton != null) {
throw new IllegalStateException("Singleton already constructed");
}
System.setSecurityManager(new SecurityManager());
}
what it does is that it prevents from calling setAccessible(true)
So when you want to call it :
Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
Constructor theConstructor = constructors[0];
theConstructor.setAccessible(true);
this exeption will occure : java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "createSecurityManager")
2nd option : In the singleton constructor, test if the call is made via Reflexion :
I refer you to this other Stackoverflow thread for the best way to get the caller class or method.
So If I add this in the Singleton constructor :
String callerClassName = new Exception().getStackTrace()[1].getClassName();
System.out.println(callerClassName);
And I call it like this :
Constructor<?>[] constructors = Singleton.class.getDeclaredConstructors();
Constructor theConstructor = constructors[0];
theConstructor.setAccessible(true);
Singleton instance1 = (Singleton) theConstructor.newInstance();
the output will be : jdk.internal.reflect.DelegatingConstructorAccessorImpl
but if I call it regularly (Instantiating a public constructor or calling a method without Reflexion) the name of the class of the calling method is printed. So for example I have :
public class MainReflexion {
public static void main(String[] args) {
Singleton.getInstance();
}
}
the callerClassName will be MainReflexion
and so the output will be MainReflexion
.
PS : If workarounds exists for the proposed solutions please let me know