How to create a singleton class

前端 未结 7 1010
粉色の甜心
粉色の甜心 2020-12-02 13:10

What is the best/correct way to create a singleton class in java?

One of the implementation I found is using a private constructor and a getInstance() method.

<
相关标签:
7条回答
  • 2020-12-02 13:51

    Best way to create Singleton Class in java is using Enums.

    Example as below :

    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    import java.io.Serializable;
    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method; 
    
    enum SingleInstance{
        INSTANCE;
    
        private SingleInstance() {
            System.out.println("constructor");
        }   
    }
    
    public class EnumSingletonDemo {
    
        public static void main (String args[]) throws FileNotFoundException, IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
        {
            SingleInstance s=SingleInstance.INSTANCE;
            SingleInstance s1=SingleInstance.INSTANCE;
    
            System.out.println(s.hashCode() + " "+s1.hashCode());//prints same hashcode indicates only one instance created
    
        //------- Serialization -------
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("sample.ser"));
        oos.writeObject(s);
        oos.close();
    
        //------- De-Serialization -------
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream("sample.ser"));
        SingleInstance s2=(SingleInstance) ois.readObject();
    
        System.out.println("Serialization :: "+s.hashCode()+" "+s2.hashCode());// prints same hashcodes because JVM handles serialization in case of enum(we dont need to override readResolve() method)
    
       //-----Accessing private enum constructor using Reflection-----
    
        Class c=Class.forName("SingleInstance");
    
        Constructor co=c.getDeclaredConstructor();//throws NoSuchMethodException
        co.setAccessible(true);
        SingleInstance newInst=(SingleInstance) co.newInstance();           
    
    }
    }
    

    NoSuchMethodException is thrown because we can't create another instance of enum 'SingleInstance' through its private constructor using Reflection.

    In Case of Serialization enum implements serializable interface by default.

    0 讨论(0)
  • 2020-12-02 13:54

    If you are using reflection to pierce encapsulation, you should not be surprised when behavior of your class is altered in incorrect ways. Private members are supposed to be private to the class. By using reflection to access them you are intentionally breaking the behavior of the class, and the resultant "duplicate singleton" is expected.

    In short: Don't do that.

    Also, you might consider creating the singleton instance in a static constructor. Static constructors are synchronized and will only run once. Your current class contains a race condition -- if two separate threads call getInstance() when it has not been previously called, there is a possibility that two instances will be created, one of them being exclusive to one of the threads, and the other becoming the instance that future getInstance() calls will return.

    0 讨论(0)
  • 2020-12-02 13:55

    just follow the singleton pattern class diagram,

    SingletonClass - singletonObject: SingletonClass - SingletonClass() + getObject(): SingletonClass

    Key point,

    • private your constructor
    • the instance of your class should be inside the class
    • provide the function to return your instance

    Some code,

    public class SingletonClass {
        private static boolean hasObject = false;
        private static SingletonClass singletonObject = null;
    
        public static SingletonClass getObject() {
            if (hasObject) {
                return singletonObject;
            } else {
                hasObject = true;
                singletonObject = new SingletonClass();
                return singletonObject;
            }
        }
    
        private SingletonClass() {
            // Initialize your object.
        }
    }
    
    0 讨论(0)
  • 2020-12-02 14:01

    I think you can check whether an instance already exists in the constructor and if exists throw an exception

    if(me != null){
        throw new InstanceAlreadyExistsException();
    }
    
    0 讨论(0)
  • 2020-12-02 14:05

    As per the comment on your question:

    I've a properties file containing some keys value pairs, which is need across the application, that is why I was thinking about a singleton class. This class will load the properties from a file and keep it and you can use it from anywhere in the application

    Don't use a singleton. You apparently don't need one-time lazy initialization (that's where a singleton is all about). You want one-time direct initialization. Just make it static and load it in a static initializer.

    E.g.

    public class Config {
    
        private static final Properties PROPERTIES = new Properties();
    
        static {
            try {
                PROPERTIES.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("config.properties"));
            } catch (IOException e) {
                throw new ExceptionInInitializerError("Loading config file failed.", e);
            }
        }
    
        public static String getProperty(String key) {
            return PROPERTIES.getProperty(key);
        }
    
        // ...
    }
    
    0 讨论(0)
  • 2020-12-02 14:14
    import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.SQLException;
    
    public class DBConnection {
    
    
        private static DBConnection dbConnection;
        private Connection connection;
    
        private DBConnection() throws ClassNotFoundException, SQLException {
            Class.forName("com.mysql.jdbc.Driver");
            connection = DriverManager.getConnection(/*crate connection*/);
        }
    
        public Connection getConnection(){
            return connection;
        }
        public static DBConnection getInstance() throws SQLException, ClassNotFoundException {
            return (null==dbConnection) ? (dbConnection = new DBConnection()) : dbConnection;
        }
    }
    
     
    
    0 讨论(0)
提交回复
热议问题