使用反射破坏和管理单例模式

        Java中可以使用反射来创建类的实例,即使类的构造方法私有时,也可以创建,这样就可能导致单例模式被破坏。比如下面非常纯的单例模式:

//非常普通的单例模式
public class Singleton {

    private static final Singleton instance = new Singleton();

    private Singleton() {

    }

    public static Singleton getInstance() {
        return instance;
    }

}

使用下面方法破坏单例:

public class SingletonKiller {
    public static void main(String[] args) throws Exception {

        /* 可以使用相对路径,同一个包中可以不用带包路径 */
        Class s = Class.forName("com.piaohan.pattern.singleton.Singleton");
        Constructor ct = s.getDeclaredConstructor();

        /* true:使java不检查访问限制,即可以使用private方法 */
        ct.setAccessible(true);

        System.out.println(Singleton.getInstance());

        System.out.println(ct.newInstance());

        System.out.println(Singleton.getInstance() == ct.newInstance());

    }
}

结果如下:

com.piaohan.pattern.singleton.Singleton@67f1fba0
com.piaohan.pattern.singleton.Singleton@3fbefab0
false

反射破坏了单例模式,但是实际开发中影响不大,项目约定好了不允许这样用就行了,很少有人会故意这么写,但是可以考虑使用这种方式结合工厂模式创建单例类,比如把所有要创建的单例类构造函数设置成私有,而正常写逻辑就行。代码如下:

//无状态业务逻辑
public class SingletonService {

    // 私有构造函数,防止外部实例化
    private SingletonService() {

    }

    // 业务逻辑1
    public void method1() {

    }

    // 业务逻辑2
    public void method2() {

    }
}

使用下面工厂生成具体的逻辑类实例对象:
//单例工厂
public class SingletonFactory {

    private static Map<Class<?>, Object> objCache = new HashMap<Class<?>, Object>();

    public synchronized static Object getInstance(Class<?> clazz) throws Exception {
        Object singleton = objCache.get(clazz);
        if (singleton == null) {
            singleton = createInstance(clazz);
            objCache.put(clazz, singleton);
        }
        return singleton;
    }

    private static Object createInstance(Class<?> clazz) throws Exception {
        Constructor ct = clazz.getDeclaredConstructor();
        ct.setAccessible(true);
        return ct.newInstance();
    }
}

这样,就不用每个类都手动写一个单例模式了,当然,这里只是思路,实际开发中要考虑性能,并发等问题。如果能够使用spring,就可以替代类似这个功能了。


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值