Java 反射机制(二)使用反射破坏单例,使用枚举加强单例

本文介绍了如何使用反射机制破坏传统的单例类,以及如何使用Java的枚举类创造出最简捷,最安全的单例。

反射的功能非常强大,普通的单例,将默认的无参构造方法私有化,但是利用反射机制任然可以实现对私有构造器的访问,实例化出多个对象。

1. 新建一个懒汉模式的单例类 SingleTonUtils.java

/**
 * 
 */
package com.jnk.think.java.chapter.reflect;

/**
 * 单例计数器
 * 
 * @author NonkeyJiang
 *
 */
public class SingleTonUtils
{
	// 私有属性
	private int timesCount;

	// 私有化无参构造器
	private SingleTonUtils()
	{
		timesCount = 0;
	}

	// 静态对象,所有用户公用一个对象
	private static SingleTonUtils singleTonUtils;

	// 获取静态对象的方法
	public static SingleTonUtils getInstance()
	{
		if (null == singleTonUtils)
		{
			singleTonUtils = new SingleTonUtils();
		}
		return singleTonUtils;
	}
}

2. 使用反射机制获取多个单例类的对象

private static void singleTonTest()
	{
		try
		{
			Class<?> obj = Class.forName("com.jnk.think.java.chapter.reflect.SingleTonUtils");// 获取Class对象
			/*
			 * 获取无参构造器,带 Declared 的方法可以获取私有方法和属性,不带 Declared 的方法只能获取公有方法和属性
			 */
			Constructor<?> constructor = obj.getDeclaredConstructor();
			constructor.setAccessible(true);// 将私有构造器的访问模式改为可以访问
			Object newInstance = constructor.newInstance();// 使用构造器创建一个新对象
			System.out.println(newInstance);// 打印对象的地址

			newInstance = constructor.newInstance();// 使用构造器创建另一个新对象
			System.out.println(newInstance);// 打印对象的地址

			/**
			 * 两次打印的对象地址不一样,证明已经存在两个不同的对象,而这个类时单例的,说明这个单例已经失效了
			 */

		} catch (Exception e)
		{
			e.printStackTrace();
		}
	}
com.jnk.think.java.chapter.reflect.SingleTonUtils@15db9742
com.jnk.think.java.chapter.reflect.SingleTonUtils@6d06d69c
两次打印的对象地址不一样,证明已经存在两个不同的对象,而这个类时单例的,说明这个单例已经失效了


3. 使用枚举得到最简洁,最纯正的单例

从Java 1.5开始实现单例可以使用一个单元素的枚举实现。

/**
 * 
 */
package com.jnk.think.java.chapter.reflect;

/**
 * @author NonkeyJiang
 *
 */
public enum EnumSingleTon
{
	TIMES(0);

	private int times;

	private EnumSingleTon(int times)
	{
		this.times = times;
	}

	public void increment()
	{
		times++;
	}

	public int getTimes()
	{
		return times;
	}

	private void p()
	{
	}
}
public static void enumSingleTonTest()
	{
		try
		{
			Class<?> obj = Class.forName("com.jnk.think.java.chapter.reflect.EnumSingleTon");// 获取Class对象

			Method[] methods = obj.getDeclaredMethods();
			for (Method method : methods)
			{
				System.out.println(method); // 没有任何构造方法的项目
			}

			Constructor<?>[] declaredMethods = obj.getDeclaredConstructors();
			System.out.println(declaredMethods.length); // 输出1
			for (Constructor<?> constructor : declaredMethods)
			{
				System.out.println(constructor);
			}

			Constructor<?> constructor = obj.getDeclaredConstructor(String.class, int.class, int.class);// 报异常java.lang.NoSuchMethodException

			constructor.setAccessible(true);// 将私有构造器的访问模式改为可以访问
			Object newInstance = constructor.newInstance();// 使用构造器创建一个新对象,报异常
															// java.lang.IllegalArgumentException:
															// Cannot
															// reflectively
															// create enum
															// objects
			System.out.println(newInstance);// 打印对象的地址
		} catch (Exception e)
		{
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

public static com.jnk.think.java.chapter.reflect.EnumSingleTon[] com.jnk.think.java.chapter.reflect.EnumSingleTon.values()
public static com.jnk.think.java.chapter.reflect.EnumSingleTon com.jnk.think.java.chapter.reflect.EnumSingleTon.valueOf(java.lang.String)
public void com.jnk.think.java.chapter.reflect.EnumSingleTon.increment()
public int com.jnk.think.java.chapter.reflect.EnumSingleTon.getTimes()
private void com.jnk.think.java.chapter.reflect.EnumSingleTon.p()
1
private com.jnk.think.java.chapter.reflect.EnumSingleTon(java.lang.String,int,int)
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
	at com.jnk.think.java.chapter.reflect.Reflect.enumSingleTonTest(Reflect.java:90)
	at com.jnk.think.java.chapter.reflect.Reflect.main(Reflect.java:38)


在使用反射机制获取枚举 EnumSingleTon的构造器的时候,可以得到这个构造器,但是在使用反射机制调用这个构造器的时候,就报异常:java.lang.IllegalArgumentException: Cannot reflectively create enum objects,不能使用反射机制创建一个枚举对象。

由于枚举类不能在外部实例化对象,并且无偿提供了序列化机制,绝对防止了多次实例化。单元素枚举已经成为实现SingleTon的最佳方式。





  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值