java对象序列化与反序列化(二)

文章目录
在远程方法调用 RMI 学习的过程中,涉及到一个概念,序列化,本文进行详述。

Java 对象的序列化和反序列化 的两种应用场景
有时候需要将 Java 对象保存永久保存,比如保存到文件中,过程:Java 对象 -> IO 对象流 -> 写入文件 -> 字符串。当我们需要将文档中的字符串恢复为 Java 对象的时候,需要相反的过程:字符串 -> 读文件 -> IO 流 -> (强制)转化为 Java 对象。
还有一种场景,在网络通信中,对象要先变为IO流经过网络传输之后,再被还原为Java对象。过程:对象 -> 写IO -> 读IO -> 对象。

序列化是一个处理对象信息的过程
序列化 (Serialization)将对象的状态信息转换为可以存储或传输的形式的过程。
反序列化是将传输信息恢复为对象的过程。

Java 对象被序列化的两种方式
方式一:Java 对象所属的类需要直接或者间接实现 Serializable接口。
方式二:Java 对象所属的类需要直接或者间接实现 Externalizable接口。这里需要注意,如果通过继承实现Externalizable接口,必须覆盖重写 writeExternal 和 readExternal 方法,否则子类新增属性无法参与序列化。

Serializable 和 Externalizable 的区别
Serializable 可以是间接或者直接实现,所在类的属性都会被序列化。
Serializable 的思路是,如果没有特殊,本类以及子类的属性将参与序列化。
Externalizable 也可以是间接实现或者直接实现,但是其参与序列化和反序列化的属相都需要通过重写方法去指定。

transient
实现 Serializable 的类 ,其属性默认都会参与序列化和反序列化,如果不想某个属性参与序列化,增加 transient 修饰即可。但是 实现 Externalizable 的类不会受transient 的影响。

private transient String other;//transient 表示该字段不参与序列化
1
Externalizable 需要覆盖重写的 writeExternal 和 readExternal 方法举例

//声明属性
private String userName;
private String password;
private int age;
private int age2;	

//get set方法略

//这两个方法无需显式调用,但是哪些属性需要序列化,则需要单独指明	
@Override
public void writeExternal(ObjectOutput out) throws IOException {
	out.writeUTF(password);
	out.writeUTF(userName);
	out.writeInt(age);
	out.writeInt(age2);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
	userName=in.readUTF();
	password=in.readUTF();
	age=in.readInt();
	age2=in.readInt();
}

序列号的生成
Java 的序列化和反序列化工作是由 JVM 完成的,在序列化和反序列化的过程中,JVM 会根据类的路径、名字、内容生成一个 long 类型的数字串(当然你也可以自己指定),这个数字串被称为序列号。

private static final long serialVersionUID = -5635658486326609381L;

序列号的生成和 JVM 的版本有关系吗?
根据我的实验,对于同一个路径下,同一个类,在内容不变的情况下,JVM 生成的序列号是一致的。测试 jdk 版本有 jdk1.6、jdk1.7、jdk1.8。

序列号是允许不显式表述的
序列号是可以不写出来的,但是要求序列化参照的类和反序列化参照的类都不写才可以。

序列号的意义
由于序列号的生成是和 类的路径、名字、内容 有关,这意味着如果你的类的内容有修改,JVM 自动生成的序列号就会有变动,如果你在类中指定了序列号,JVM 就会以你指定的为准。这样做是有好处的,可以提醒你远程交互中两端的类的版本不一致。但是这也有弊端,对于远程调用来说,如果一方
实体类有变动,那么双方生成的序列号可能就不一样。所以序列号是为了保证序列化和反序列化双方的一致性。

一定要显式的指定序列号
由于我们无法确保类的内容不会更改,所以一定要写序列号,这个是可以自定义的,比如写成1L。

Java 对象序列化会影响性能且需要平台一致性
显然序列化会影响性能,而且需要同为 Java 平台。

序列化应用的简单测试——以对象保存到 txt 中为例
实体类
package common;
import java.io.Serializable;
public class Model implements Serializable{
private static final long serialVersionUID = -3265803653258922833L;

private String userName;
private String password;
private transient int age;
private int age2;
private transient String other;//transient 表示该字段不参与序列化
//get\set 方法 略

//如果 implements Externalizable ,需在下面的方法中指明需序列化个反序列化字段
//序列化字段
/*@Override
public void writeExternal(ObjectOutput out) throws IOException {
	
	out.writeUTF(password);
	out.writeUTF(userName);
	out.writeInt(age);
	out.writeInt(age2);
}
//反序列化字段
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
	userName=in.readUTF();
	password=in.readUTF();
	age=in.readInt();
	age2=in.readInt();
}*/

}

测试方法
package common;

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

public class Test {

//文件路径和名字
private static String filePath="D://a.txt";


public static void main(String[] args) {
	Model m=new Model();
	m.setUserName("jecket");
	m.setPassword("123456");
	m.setOther("other");
	System.out.println(ToStringBuilder.reflectionToString(m));
	//写到文件
	jdkSerializableWrite(filePath,m);
	
	//从文件读取
	Model m2=jdkSerializableRead(filePath);
	System.out.println(ToStringBuilder.reflectionToString(m2));
}

/**
 * 将对象序列化写入 txt 文件
 * @param <T>
 * @param t
 */
public static <T> void jdkSerializableWrite(String filePath,T t){
    try {
       ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream(filePath));
       oos.writeObject(t);
       oos.close();

   } catch (FileNotFoundException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
   } catch (IOException e) {
       // TODO Auto-generated catch block
       e.printStackTrace();
   }  

}
/**
* 读取 序列化对象 从txt文件
* @param
* @param filePath
* @return
*/
public static T jdkSerializableRead(String filePath) {
try {
@SuppressWarnings(“resource”)
ObjectInputStream ois=new ObjectInputStream(new FileInputStream(filePath));
return (T) ois.readObject();

        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
	return null; 
}

}

原文链接:https://blog.csdn.net/bestcxx/article/details/79425136

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值