Java 单例模式 工具类

[b][color=red][size=medium]本文版权归作者所有,仅供用来网上学习来用,读者可以收藏,请不要下载到本机和重新发布到其它网站[/size][/color][/b]

有觉得可以改进的,请留言,也可加群讨论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)方法
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值