Java: Effective java learning notes strengthen the SIngleton attribute with a private constructor or enumeration type

Strengthen the SIngleton attribute

1. Singleton mode

Hi, let's talk about a single example of Java

Before the release of Java 1.5, there were two ways to implement Singleton (hungry and lazy). Both methods keep the constructor private and export public static members to allow clients to access a unique instance of the class.

Type 1: lazy type

/**
 * @description: Lazy -- implementation of singleton
 **/
public class SingleTonLanHan  {
    /**
     *  Privatization constructor
     */
    private SingleTonLanHan (){}

    private static SingleTonLanHan  singleTonLanHan;

    public static  SingleTonLanHan getSingleTonLanHan(){
        if (singleTonLanHan == null){
            singleTonLanHan = new SingleTonLanHan();
        }
        return singleTonLanHan;
    }
}


Type 2: hungry Han style

/**
 * @description: Hungry Chinese style -- implementation of single example
 **/
public class SingleTonEh {
    /**
     *  Privatization constructor
     */
    private SingleTonEh(){}

    private static SingleTonEh singleTonEh = new SingleTonEh();

    public static SingleTonEh getSingleTonEh(){
        return singleTonEh;
    }
}

2. Static member mode

public class Singleton {

    public static final Singleton singleton = new Singleton();

    private Singleton() {
        if (singleton != null)
            throw new RuntimeException("Structural anomaly");
    }

    public void doSomething(){}
}

In the above code, keep the private constructor and provide a static final attribute to complete the initialization of the object. In java, privileged clients can call the private constructor through the reflection mechanism AccessibleObject.setAccessible. Therefore, in order to prevent this problem, throw an exception when the private constructor guarantees the second call, To avoid generating objects by calling private constructor methods through reflection

3. Strengthen with private constructors

It is very simple to declare the constructor as a private type, but it should be noted that the privileged client can use the reflection mechanism to call the private constructor. In order to further ensure the uniqueness of the singleton, we can judge whether the unique instance exists in the private constructor, and throw an exception if it exists, like this:

public class Singleton {
        private static final Singleton INSTANCE = new Singleton();

        private Singleton() {
            if (INSTANCE != null) {
                throw new UnsupportedOperationException("Instance already exist");
            }
        }

        public static Singleton getInstance() {
            return INSTANCE;
        }}

Can this absolutely prevent multiple instances? NO!

Now there is another case where multiple instances will appear, that is, after you serialize the object, you will get a new object again. Do you believe it? Come on, the code says everything:

1) First, implement the Serializable interface with the above code:

public class Singleton implements Serializable{
                        ...
   }

2) . start the serialization test, and the test code is as follows (ensure simplicity and understanding, but not rigor):

public class SerializableTest {
        @Test
        public void serializableTest() throws Exception{
            serializable(Singleton.getInstance(), "test");
            Singleton singleton = deserializable("test");
            Assert.assertEquals(singleton, Singleton.getInstance());
        }

        //serialize
        private void serializable(Singleton singleton, String filename) throws IOException {
            FileOutputStream fos = new FileOutputStream(filename);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(singleton);
            oos.flush();
        }
        //Deserialization
        @SuppressWarnings("unchecked")
        private <T> T deserializable(String filename) throwsIOException,
                                                ClassNotFoundException {
            FileInputStream fis = new FileInputStream(filename);
            ObjectInputStream ois = new ObjectInputStream(fis);
            return (T) ois.readObject();
        }}

Reported an error and got two different objects
It can be seen from the results that two different objects are obtained, one Singleton@deb6432 And one Singleton@1b4fb997 ;

Well, of course, there are solutions. You just need to add the following method to the singleton class:

public class Elvis {
    public static final Elvis INSTANCE = new Elvis();

    private Elvis() {
    }

    public void leaveTheBuilding() {
        System.out.println("Whoa baby, I'm outta here!");
    }

    private Object readResolve() {
        // Return the one true Elvis and let the garbage collector
        // take care of the Elvis impersonator.
        return INSTANCE;
    }

    // This code would normally appear outside the class!
    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }
}

All calls to the static method Elvis.getinstance() will return the same object reference, so no other Elvis instance will be created.

be careful:

You want this class to be programmatically serializable. It is not enough to just add implements Serializable on the class declaration. In order to maintain and ensure Singleton, it must declare that all instance fields are transient.

4. Using enumeration to implement singleton mode

The enumeration of single elements is used to implement Singleton, which absolutely prevents multiple instantiations. The above problems will not occur here. The implementation code is as follows:

public enum Elvis {
    INSTANCE;

    public void leaveTheBuilding() {
        System.out.println("Whoa baby, I'm outta here!");
    }

    // This code would normally appear outside the class!
    public static void main(String[] args) {
        Elvis elvis = Elvis.INSTANCE;
        elvis.leaveTheBuilding();
    }

reference resources

1,Strengthen the SIngleton property with a private constructor or enumeration type
2,Effective Java Reading Note 3 strengthens the Singleton attribute with a private constructor or enumeration type
3,Article 3: strengthen the Singleton attribute with a private constructor or enumeration type

Tags: Java

Posted on Wed, 24 Nov 2021 19:51:35 -0500 by ldtiw