用私有构造器或者枚举强化单例(三)

用私有构造器或者枚举强化单例

首先对单单例,构造函数需要私有化,这样能够极大的保障外部无法直接实例化该对象
单例在面试中经常会有面试官要求写,下面列出几种常用的写法:

懒汉式(线程不安全写法,与之相对的还有线程安全的写法不赘述)

1
2
3
4
5
6
7
8
9
10
 public class Singleton {  
    private static Singleton instance;  
    private Singleton (){}   
    public static Singleton getInstance() {  
     if (instance == null) {  
          instance = new Singleton();  
      }  
      return instance;  
      }  
   }

饿汉式(线程不安全写法,与之相对的还有线程安全的写法不赘述)

1
2
3
4
5
6
7
 public class Singleton {  
     private static Singleton instance = new Singleton();  
     private Singleton (){}
     public static Singleton getInstance() {  
     return instance;  
     }  
 }

对于上面这种写法,在书中有提到如果首行代码是public的话可以通过反射机制多实例化对象。如下举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
package com.stardust.effective.role3;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

/**
* Created by mike on 2017/12/3.
*/
public class Singleton {

public static Singleton instance = new Singleton();

private Singleton() { }

public static Singleton getInstance() {
return instance;
}

public static void main(String[] args) {
Singleton s1 = null;
Singleton s2 = null;
Singleton s3 = Singleton.getInstance();
Singleton s4 = Singleton.getInstance();

if (s3==s4){
System.out.println("通过静态工厂获取到的单例是唯一的");
}else {
System.out.println("静态工厂获取的单例不唯一");
}

Constructor<?> constructor = Singleton.class.getDeclaredConstructors()[0];
constructor.setAccessible(true);
try {
s1 = (Singleton) constructor.newInstance();
s2 = (Singleton) constructor.newInstance();
if(s1!=s2){
System.out.println("构造出两个不同的实例");
}else {
System.out.println("始终为单例");
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}

}

枚举实现单例,这个是effective java书中推荐的实现方式,枚举天然私有构造,final,static等特性,可以生产一个懒加载的单例

1
2
3
4
5
6
public enum Singletons {
    INSTANCE;
    public void say() {
        System.out.println("animal say");
    }
}

从网上找的一个具体的例子,SomeThing.INSTANCE.getInstance() 即可获得所要实例

1
2
3
4
5
6
7
8
9
10
11
12
13
class Resource{
}

public enum SomeThing {
INSTANCE;
private Resource instance;
SomeThing() {
instance = new Resource();
}
public Resource getInstance() {
return instance;
}
}

分享到