Effective Java:对于实例控制,枚举类型优先于readResolver

对于实例控制,枚举类型优先于readResolver

readResolve方法:对于一个正在被反序列化的对象,如果它的类正确的定义了一个readResolve方法,那么在反序列化之后,新建对象上的readResolve方法会被调用,该方法返回的对象引用将被返回,取代新建的对象.新建的对象引用没有保留,立即成为垃圾回收的对象.

一般用于单例设计模式中确保实现序列化接口的单例类的正确性

如果依赖readResolve进行实例控制,带有对象引用类型的所有实例域都必须被声明为transient的,否则,那种破釜沉舟式的攻击者,就有可能在readResolve方法运行之前,保护只想反序列化对象的引用

思路:如果包含一个非transient的对象属性,这个域的内容就可以在readResolve方法运行之前被反序列化,此时可能会有一个精心制作的流"盗用"指向最初被反序列化的对象的引用

/**
 * 有问题的Singleton
 */
public class Elvis implements Serializable {

	public static final Elvis INSTANCE = new Elvis();
	
	private String[] favoriteSongs = {"song01", "song02"};
	
	private Elvis() {}
	
	public void printFavorites() {
		System.out.println(Arrays.toString(favoriteSongs));
	}
	
	private Object readResolve() {
		return INSTANCE;
	}
}

/**
 * 盗用者类
 */
public class ElvisStealer implements Serializable {
	
	static Elvis impersonator;
	
	private Elvis payload;

	private Object readResolve() {
		impersonator = payload;
		return new String[] {"text"};
	}
}

public class ElvisImpersonator {

	private static final byte[] serializedForm = new byte[] {
			(byte) 0xac, (byte) 0xed, (byte) 0x00, (byte) 0x05
			// ...
	};
	
	public static void main(String[] args) {
		Elvis elvis = (Elvis) deserialized(serializedForm); // 反序列化方法略
		Elvis impersonator = ElvisStealer.impersonator;
		
		elvis.printFavorites(); // [song01, song02]
		impersonator.printFavorites(); // [text]
	}
}

最好是把单例做成是一个单元素的枚举类型,自从jdk1.5发行依赖,readResolve方法就不再是在可序列化类中维持单例的最佳方法了,如果将一个可序列化的单例类编写为枚举,就可以绝对保障除了所声明的常量以外,不会有别的实例,JVM提供了保障

如果单例类的实例在编译时还不知道,我们就无法采用枚举的方式,因此readResolve方法并不过时

readResolve方法的可访问性很重要,在final类中他应该是私有的(private),如果readResolve方法是protected的,且在子类中如果没有重写它,在反序列化的时候会产生一个父类的实例,从而产生ClassCastException

结论:

  1. 尽可能的使用枚举实现单例
  2. 不能使用枚举的单例使用readResolve方法,同时控制对象属性为transient的
  3. 如果要使用readResolve方法,需要谨慎考虑其可访问性
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值