3. 用私有构造器或枚举类型强化singleton属性

Effective Java 中提出实现单例的3中方法,详细内容如下:

1.将公有静态成员变量做成final域

package com.jason.effectivejava.rule3.one;

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

public class Elvis {

	public static final Elvis INSTANCE = new Elvis();

	private Elvis() {
               //it is very import for this type
		if(INSTANCE != null){
			throw new IllegalArgumentException("No exist the second instance");
		}
	}

	public void leaveTheBuilding() {

		System.out.println("Whoa baby, I'm outta here!");

	}

	public static void main(String[] args) {

		Elvis singleton = Elvis.INSTANCE;
		singleton.leaveTheBuilding();
		Constructor[] arrayConstructor = singleton.getClass().getDeclaredConstructors();
		arrayConstructor[0].setAccessible(true);
		
		try {
			arrayConstructor[0].newInstance();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}

 注意:为了防止特殊用户通过AccessibleObject.setAccessible方法,利用反射机制访问私有构造函数,创建新的实例,应在私有构造函数中添加判断,阻止创建新的实例。

测试结果如下:

Whoa baby, I'm outta here!
java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at com.jason.effectivejava.rule3.Elvis.main(Elvis.java:30)
Caused by: java.lang.IllegalArgumentException: No exist the second instance
	at com.jason.effectivejava.rule3.Elvis.<init>(Elvis.java:12)
	... 5 more

2.将公有成员变量做成静态工厂方法

package com.jason.effectivejava.rule3.two;

public class Elvis {

	private static final Elvis INSTANCE = new Elvis();

	private Elvis() {
	}

	public static Elvis getInstance() {
		return INSTANCE;
	}

	public void leaveTheBuilding() {

		System.out.println("Whoa baby, I'm outta here!");
	}

	// 必须提供该方法,以便重新指定反序列化得到的对象.
	private Object readResolve(){

		return INSTANCE;
	}

	public static void main(String[] args) {

		Elvis elvis = Elvis.getInstance();
		elvis.leaveTheBuilding();
	}
}

3.单元素枚举类型

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
*
*枚举实现单例
*<p>目前最好的方式,避免了反射的攻击和序列化的问题
*
*反射调用枚举私有构造函数测试结果:
* Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
at java.lang.reflect.Constructor.newInstance(Unknown Source)
at com.book.chap2.singleton.Singleton3.main(Singleton3.java:34)
*
*/

public enum Elvis {

	INSTANCE;

	public void leaveTheBuilding() {

		System.out.println("Whoa baby, I'm outta here!");
	}

	public static void main(String[] args) {

		Elvis elvis = Elvis.INSTANCE;
		elvis.leaveTheBuilding();
		
		//测试,是否可以反射生成枚举,利用反射调用私有构造器
		Constructor[] arrayConstructor=Elvis.INSTANCE.getClass().getDeclaredConstructors();

		arrayConstructor[0].setAccessible(true);
		try {
			arrayConstructor[0].newInstance();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
}

 试结果:

Whoa baby, I'm outta here!
java.lang.IllegalArgumentException: Cannot reflectively create enum objects
	at java.lang.reflect.Constructor.newInstance(Constructor.java:511)
	at com.jason.effectivejava.rule3.two.Elvis.main(Elvis.java:36)

 总结:

在三种方法中,单元素枚举类型的单例,代码简洁,无偿提供序列化机制,同时可防止多次实例化,在实际中应该是最佳选择。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值