Effective Java(二)之用私有构造器或者枚举类型强化Singleton属性

本文详细探讨了单例模式的三种实现方式:公有静态成员、静态工厂方法及单元素枚举类型。针对每种方式的特点,特别是如何防范反射攻击和序列化问题进行了深入分析。

书上分别说了以下三种

 

        1)将公有静态成员做成final域享有特权的客户端可以借助AccessibleObject.setAccessible方法,通过反射机制调用私有构造器。

package com.lzw.singleton1;

import java.lang.reflect.Constructor;

/**
 * 
 * 单例实现1
 * <p>
 * 公有静态成员是个public final域
 * <p>
 * 为防止client利用反射调用私有改造函数,所以在创建第二个实例的时候抛出了异常
 * 
 * @author troyli
 * 
 */

public class Singleton1 {
	public static final Singleton1 INSTANCE = new Singleton1();

	// 私有改造函数
	private Singleton1() {
		if (INSTANCE != null) {
			throw new IllegalArgumentException("不存在第二个实例对象……");
		}
	}

	// 其他方法实现
	public void otherMethod() {
		System.out.println("call otherMethod");
	}

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static void main(String args[]) throws Exception {
		Singleton1 singleton = Singleton1.INSTANCE;
		singleton.otherMethod();

		// 利用反射调用私有构造器
		Constructor[] arrayConstructor = singleton.getClass()
				.getDeclaredConstructors();
		for (Constructor constructor : arrayConstructor) {
			// 调用setAccessible(true);
			constructor.setAccessible(true);

			// 实例化,这里一定会抛出异常
			constructor.newInstance();
		}
	}
}

 

       问题:为什么会抛出异常(不存在第二个实例对象……),这里我们分析一下代码的执行顺序。

             ①JVM 装载类的静态成员变量:public static final Singleton1 INSTANCE;

             ②执行入口方面main;

             ③获取实例对象:Singleton1 singleton = Singleton1.INSTANCE;也就会执行private Singleton1(){……}

             ④执行newInstatnce:constructor.newInstance();就会是在已经有一个对象的时候重新调用private Singleton1(){……},于是就会抛出异常。

        2)将公有静态成员做成final域和将公有成员做成静态工厂方法时,为了使Singleton类变成可序列化的,仅仅在声明上加上“implements Serializable”是不够的。

为了维护并保证Singleton,必须声明所有实例域都是瞬时的(transient),并提供一个readResolve方法。否则,每次反序列化一个序列化的实例时,都会创建一个新的实例。

package com.lzw.singleton2;

import java.io.Serializable;

/**
 * 
 *单例实现2
 *<p>
 * 公有的成员为静态工厂方法
 *<p>
 * 序列化时,要实现readResolve方法,防止反序列化出新的实例(这个应该怎么测试呢???)
 * 
 *@author troyli
 * 
 */

public class Singleton2 implements Serializable {
	// 私有static Instance
	private static final Singleton2 INSTANCE = new Singleton2();

	// 私有构造函数
	private Singleton2() {
	}

	// 获取单例方法
	public static Singleton2 getInstance() {
		return INSTANCE;
	}

	// 其他方法
	public void otherMethod() {
		//
	}

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

 

       这点对我是全新的东西,因此也在积累中……

       3)单元素枚举类型更加简洁、无偿的提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击时;它已经成为实现Singleton的最佳方法。

package com.lzw.singleton3;

import java.lang.reflect.Constructor;

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

public class Singleton3 {
	enum EnumSingleton {
		INSTANCE;

		public void otherMethod() {
		}

	}

	// 测试,是否可以反射生成枚举
	public static void main(String args[]) throws Exception {
		// 利用反射调用私有构造器
		Constructor[] arrayConstructor = EnumSingleton.INSTANCE.getClass()
				.getDeclaredConstructors();
		for (Constructor constructor : arrayConstructor) {
			// 调用setAccessible(true),设置为可以访问;
			constructor.setAccessible(true);

			// 实例化,这里一定会抛出异常
			constructor.newInstance();
		}
	}
}

 

        可以看上面的第一种的问题解析,这里不再重复。

       虽然这种方法目前还没有被广泛采用,但是单元素的枚举类型已经成为实现Singleton的最佳方法。

【EI复现】基于深度强化学习的微能源网能量管理与优化策略研究(Python代码实现)内容概要:本文围绕“基于深度强化学习的微能源网能量管理与优化策略”展开研究,重点利用深度Q网络(DQN)等深度强化学习算法对微能源网中的能量调度进行建模与优化,旨在应对可再生能源出力波动、负荷变化及运行成本等问题。文中结合Python代码实现,构建了包含光伏、储能、负荷等元素的微能源网模型,通过强化学习智能体动态决策能量分配策略,实现经济性、稳定性和能效的多重优化目标,并可能与其他优化算法进行对比分析以验证有效性。研究属于电力系统与人工智能交叉领域,具有较强的工程应用背景和学术参考价值。; 适合人群:具备一定Python编程基础和机器学习基础知识,从事电力系统、能源互联网、智能优化等相关方向的研究生、科研人员及工程技术人员。; 使用场景及目标:①学习如何将深度强化学习应用于微能源网的能量管理;②掌握DQN等算法在实际能源系统调度中的建模与实现方法;③为相关课题研究或项目开发提供代码参考和技术思路。; 阅读建议:建议读者结合提供的Python代码进行实践操作,理解环境建模、状态空间、动作空间及奖励函数的设计逻辑,同时可扩展学习其他强化学习算法在能源系统中的应用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值