Usually we use the single example pattern, we can use reflection to make it no longer a single example, the following a hungry man-style single case pattern:
Public final class Singleton {
private static final Singleton instance=new Singleton ();
Private Singleton () {public
static Singleton getinstance () {return
instance;
}
}
The test cases are as follows:
Singleton singleton1=singleton.getinstance ();
Singleton singleton2=singleton.getinstance ();
Constructor<singleton> constructor=singleton.class.getdeclaredconstructor ();
Constructor.setaccessible (true);
Singleton singleton3=constructor.newinstance ();
System.out.println (singleton1);
System.out.println (singleton2);
System.out.println (Singleton3);
System.out.println (singleton1==singleton2);
System.out.println (Singleton1==singleton3);
Where Singleton1 and Singleton2 are the objects that are obtained through the single example pattern we implement, they should be the same object, and Singleton3 gets the parameterless constructor by reflection Constructor.setaccessible (True) To gain access, and finally create an object through the parameterless constructor Singleton3,singleton3 and the above should not be the same object, the test results are as follows:
com.lg.design.singleton.hungry.singleton@15e3d24a
com.lg.design.singleton.hungry.singleton@15e3d24a
Com.lg.design.singleton.hungry.singleton@20030380
true
false
So usually we use the single case pattern, we can use reflection to make it no longer a single example. However, a single example uses enumerations to avoid being reflected.
The single example is as follows:
public enum Singleton {
instance;
Private Singleton () {}
}
Reflection is as follows:
Singleton singleton1=singleton.instance;
Singleton singleton2=singleton.instance;
Constructor<singleton> constructor=singleton.class.getdeclaredconstructor ();
Constructor.setaccessible (true);
Singleton singleton3=constructor.newinstance ();
System.out.println (singleton1);
System.out.println (singleton2);
System.out.println (Singleton3);
System.out.println (singleton1==singleton2);
System.out.println (Singleton1==singleton3);
Then the error is:
Exception in thread "main" java.lang.nosuchmethodexception:com.lg.design.singleton.enumsingleton.singleton.< Init> () at
java.lang.Class.getConstructor0 (class.java:2849)
at Java.lang.Class.getDeclaredConstructor (class.java:2053) at
Com.lg.design.singleton.enumsingleton.Test.main (test.java:14)
Without this parameterless constructor, by debugging Singleton.class.getDeclaredConstructors () to get all the constructors, you will find that there is no parameterless constructor that we set, only one argument is (String.class, Int.class) constructor, and then we can see that the argument here is actually the name of the enumeration and the position in the enumeration, that is, the name and ordinal two attributes of the enumeration, the source of the enumeration is as follows:
Public abstract class Enum<e extends enum<e>>
implements Comparable<e>, Serializable {
Private final String name;
Public final String name () {return
name;
}
private final int ordinal;
Public final int ordinal () {return
ordinal;
}
Protected Enum (String name, int ordinal) {
this.name = name;
This.ordinal = ordinal;
}
Public String toString () {return
name;
}
Slightly
}
Enum Enum is an abstract class, once a class is declared as an enumeration, in fact, it inherits the enum, so there will be (String.class,int.class) the constructor (the constructor of the parent enum), the specific principle can be based on the generated bytecode back to the compiler learned that, can refer to this article http://pf-miles.iteye.com/blog/187155#bc2340028.
Now that you can get the constructor for the parent enum, we use the constructor to see if we can create an object:
Singleton singleton1=singleton.instance;
Singleton singleton2=singleton.instance;
Constructor<singleton> Constructor=singleton.class.getdeclaredconstructor (String.class,int.class);
Constructor<singleton> constructor=singleton.class.getdeclaredconstructor ();
Constructor.setaccessible (true);
Singleton singleton3=constructor.newinstance ("Otherinstance", 9);
Singleton singleton3=constructor.newinstance ();
System.out.println (singleton1);
System.out.println (singleton2);
System.out.println (Singleton3);
System.out.println (singleton1==singleton2);
System.out.println (Singleton1==singleton3);
Then it also complains:
Exception in thread ' main ' java.lang.IllegalArgumentException:Cannot reflectively create enum objects at
Java.lang.reflect.Constructor.newInstance (constructor.java:521) at
Com.lg.design.singleton.enumsingleton.Test.main (TEST.JAVA:16)
Before the mistake is that there is no constructor, this time we can get the constructor, but only when using the constructor to execute the newinstance ("Otherinstance", 9) method throws an exception, said can not reflect the enumeration, the specific source code is as follows:
Public T newinstance (Object ... initargs)
throws Instantiationexception, Illegalaccessexception,
IllegalArgumentException, invocationtargetexception
{
if (!override) {
if (!) Reflection.quickcheckmemberaccess (Clazz, modifiers)) {
class<?> caller = Reflection.getcallerclass ();
CheckAccess (caller, clazz, NULL, modifiers);
}
Our focus is that if the class contains an ENUM modifier, the method is invoked directly with the error if
((Clazz.getmodifiers () & Modifier.enum)!= 0)
throw new IllegalArgumentException ("Cannot reflectively create enum objects");
Constructoraccessor CA = constructoraccessor; Read volatile
if (ca = = null) {
CA = Acquireconstructoraccessor ();
}
Return (T) ca.newinstance (Initargs);
}
That is, reflection, when an object is created through newinstance, checks whether the class is an enumerated class and, if so, throws an exception and the reflection fails.
That is to say, using enumerations avoids reflection, and thus can achieve a single example.