关于java中Serializable序列化问题中属性赋值总结

java 提供Serializable解决对象可持久化的问题,它为分布式或者异构的环境下java对象的传输提供了先决支持条件。在序列化和反序列化的时候,如果在server/client 端 传输对象的类型版本变更 可能导致无法反序列化生成所需要的对象。如Person类只有name属性 在序列化后,如果Person类此时添加另一个属性 age  这个时候反序列化就会报错InvalidClassException 异常。原因是序列化和反序列化所对应的类型版本不一致,而java如何判断他们的版本不一致呢,她是根据SerialVersionUID 流标识符判断的,在实现Serializable接口的时候 我们应该显式的声明uid 如果没显式声明,jvm在编译的时候会隐式计算出这个uid 所以上述问题在版本更替的时候,如果在Person 中显示声明的话,向jvm“撒谎”认为版本一致就可以避免InvalidClassException 异常的发生,并顺利转换生成所需要的对象,只是反序列化的对象没有新增的功能。但是开发过程中尽量保证两端类型完整一致。

先提供测试类

person

package test;

import java.io.Serializable;

/**
 * 
 * @see		
 * @author  Hu
 * @date	2015-3-5 下午2:47:33
 * @version	 
 * @desc    TODO
 */
public class Person implements Serializable{
	/**
	 * uid
	 */
	private static final long serialVersionUID = 6043921487754688987L;
	
	
	private String normal ="normal1";
	private transient String transientStr= "transientStr1";
	private final String  finalStr="finalStr1";
	@Override
	public String toString() {
		return "Person [normal=" + normal + ", transientStr=" + transientStr + ", finalStr=" + finalStr + "]";
	}
	
	
}

SerializableUtils

package test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

/**
 * 
 * @see
 * @author Hu
 * @date 2015-3-5 下午2:51:44
 * @version
 * @desc TODO
 */
public class SerializableUtils {
	private final static String fp = "d:/SerializableUtils.txt";

	/**
	 * 序列化服务
	 * @param o
	 */
	public static void serializeObj(Serializable o) {
		try {
			ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(fp));
			oos.writeObject(o);
			oos.close();
		} catch (Exception e) {
			throw new RuntimeException("反序列化失败");
		} 
	}

	/**
	 * 反序列化服务
	 * @return
	 */
	public static Object deserializeObj() {
		ObjectInputStream ois = null;
		try {
			ois = new ObjectInputStream(new FileInputStream(fp));
			return ois.readObject();
		} catch (Exception e) {
			throw new RuntimeException("");
		} finally{
			if(ois!=null){
				try {
					ois.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

1.当调用serializeObj(new Person())服务的时候 person对象被以流的形式保存的文件中,在反序列化调用deserializeObj

public static void main(String[] args) {
		Person person = new Person();
		SerializableUtils.serializeObj(person);
		Object obj = SerializableUtils.deserializeObj();
		System.out.println(obj);
		
	}

生成的结果如下:

Person [normal=normal1, transientStr=null, finalStr=finalStr1]

总结:修饰符transient修饰的属性不会被写入留中,所以反序列化的时候 默认值null初始化对象

2.修改Person初始化的值如下

package test;

import java.io.Serializable;

/**
 * 
 * @see		
 * @author  Hu
 * @date	2015-3-5 下午2:47:33
 * @version	 
 * @desc    TODO
 */
public class Person implements Serializable{
	/**
	 * uid
	 */
	private static final long serialVersionUID = 6043921487754688987L;
	
	
	private String normal ="normal2";
	private transient String transientStr= "transientStr2";
	private final String  finalStr="finalStr2";
	@Override
	public String toString() {
		return "Person [normal=" + normal + ", transientStr=" + transientStr + ", finalStr=" + finalStr + "]";
	}
	
	
}

测试代码

public static void main(String[] args) {
		Person person = new Person();
		Object obj = SerializableUtils.deserializeObj();
		System.out.println(obj);
		
	}

结果:

Person [normal=normal1, transientStr=null, finalStr=finalStr2]

总结: 反序列化过程中final常量从新计算生成最新的常量

3.构造函数和方法初始化变量(将属性赋值在构造函数里面初始化)

package test;

import java.io.Serializable;

/**
 * 
 * @see
 * @author Hu
 * @date 2015-3-5 下午2:47:33
 * @version
 * @desc TODO
 */
public class Person implements Serializable {
	/**
	 * uid
	 */
	private static final long serialVersionUID = 6043921487754688987L;

	private String normal;
	private transient String transientStr;
	private final String finalStr;

	public Person() {
		normal = "normal3";
		transientStr = "transientStr3";
		finalStr = "finalStr3";
	}

	@Override
	public String toString() {
		return "Person [normal=" + normal + ", transientStr=" + transientStr + ", finalStr=" + finalStr + "]";
	}
        
}

测试代码:

public static void main(String[] args) {
		Person person = new Person();
		Object obj = SerializableUtils.deserializeObj();
		System.out.println(obj);
		
	}

结果:

Person [normal=normal1, transientStr=null, finalStr=finalStr1]

总结:从2中知道final在反序列化的时候需要重新计算生成值,但是这里反序列化的时候却仍然是第一次序列化的时候的值,这是因为jvm在反序列化的时候不执行构造函数和初始化函数,所以值都是最原始的初始值,而final虽然从新计算但是jvm发现finalStr未被初始化,jvm就直接将序列化中的初始值返回给生成的对象。



转载于:https://my.oschina.net/ehomeud/blog/383116

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值