[b][color=red][size=medium]本文版权归作者所有,仅供用来网上学习来用,读者可以收藏,请不要下载到本机和重新发布到其它网站[/size][/color][/b]
有觉得可以改进的,请留言,也可加群讨论71326533
我们在实际开发中,会大量采用单例模式。但是我们常常疲于写那几个单调的方法,还可考虑同步的问题,下面就是一个常用的单例模式的写法:
为了减少重复的写这些无聊的代码,我写了一个类,用来统一管理这些单例对象
用法很简单
[b]结果:[/b]
true
这里统一管理这些单例对象,且单例对象的构造器可以为私有的。如果需要带参数,则需要使用public static <T> T getInstance(Class<? extends T> clazz, Class<?>[] parameterTypes, Object[] args)方法
有觉得可以改进的,请留言,也可加群讨论71326533
我们在实际开发中,会大量采用单例模式。但是我们常常疲于写那几个单调的方法,还可考虑同步的问题,下面就是一个常用的单例模式的写法:
public class Singleton {
private Singleton() {
}
... ...
... ...
}
为了减少重复的写这些无聊的代码,我写了一个类,用来统一管理这些单例对象
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SingletonFactory {
public static final Logger LOG = Logger.getLogger(SingletonFactory.class.getCanonicalName());
private static final Map<Class<?>, Object> INSTANCE_MAP = Collections.synchronizedMap(new HashMap<Class<?>, Object>());
private static final Object[] EMPTY_ARGS = new Object[0];
/**
* <pre>
* 用此方法有一个前提:
* 参数类必须有显示声明的无参构造器或没有任何显示声明的构造器
* </pre>
*/
public static <T> T getInstance(Class<? extends T> clazz) {
return getInstance(clazz, EMPTY_ARGS);
}
/**
* <pre>
* 用此方法有两个前提:
* 1. 参数数组的项都不能为null
* 2. 参数数组的项都不能是简单数据类型
* </pre>
*/
public static <T> T getInstance(Class<? extends T> clazz, Object... args) {
Object object = INSTANCE_MAP.get(clazz);
if (object == null) {
Class<?>[] parameterTypes = new Class<?>[args.length];
for (int i = 0; i < args.length; i++) {
parameterTypes[i] = args[i].getClass();
}
return getInstance(clazz, parameterTypes, args);
}
return clazz.cast(object);
}
/**
* <pre>
* 用此方法有三个前提:
* 1. 两个参数数组同时为null或同时不为null
* 2. 两个数组的长度必须相等
* 3. parameterTypes如果不空null, 则其各元素不能为null
* </pre>
*/
public static <T> T getInstance(Class<? extends T> clazz, Class<?>[] parameterTypes, Object[] args) {
Object object = INSTANCE_MAP.get(clazz);
if (object == null) { // 检查实例,如是不存在就进行同步代码区
synchronized (clazz) { // 对其进行锁,防止两个线程同时进入同步代码区
// 双重检查,非常重要,如果两个同时访问的线程,当第一线程访问完同步代码区后,生成一个实例;当第二个已进入getInstance方法等待的线程进入同步代码区时,也会产生一个新的实例
if (object == null) {
try {
if (parameterTypes != null && args != null) {
if (parameterTypes.length == args.length) {
Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes);
constructor.setAccessible(true);
T instance = clazz.cast(constructor.newInstance(args));
INSTANCE_MAP.put(clazz, instance);
return instance;
} else {
throw new IllegalArgumentException("参数个数不匹配");
}
} else if (parameterTypes == null && args == null) {
T instance = clazz.newInstance();
INSTANCE_MAP.put(clazz, instance);
return instance;
} else {
throw new IllegalArgumentException("两个参数数组必须同时为null或同时不为null");
}
} catch (Exception e) {
LOG.log(Level.SEVERE, "创建实例失败", e);
}
}
}
}
return null;
}
}
用法很简单
public class SingletonTest {
public static void main(String[] args) {
Singleton obj1 = SingletonFactory.getInstance(Singleton.class);
Singleton obj2 = SingletonFactory.getInstance(Singleton.class);
System.out.println(obj1 == obj2);
}
}
[b]结果:[/b]
true
这里统一管理这些单例对象,且单例对象的构造器可以为私有的。如果需要带参数,则需要使用public static <T> T getInstance(Class<? extends T> clazz, Class<?>[] parameterTypes, Object[] args)方法