Java——transient and 序列化
来源:互联网 发布:淘宝主图视频软件 编辑:程序博客网 时间:2024/05/07 02:17
序列化
序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。
在网络传输过程中,可以是字节或是XML,json等格式。而字节的,XML,json编码格式可以还原完全相等的对象。这个相反的过程又称为反序列化。
transient
java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。
序列化两种方式
1.对象实现了序列化接口Serializable
2.第二种方式为实现接口Externalizable
其实这个接口也是继承了Serializable接口,该接口中有两个方法 void writeExternal(ObjectOutput out)
和 void readExternal(ObjectInput in)
,所以使用这种方式,要实现这两个接口。在 writeExternal()
方法里定义了哪些属性可以序列化,例如 out.writeObject(userName)
,哪些不可以序列化,对象在经过这里就把规定能被序列化的序列化保存文件,不能序列化的不处理,然后在反序列的时候自动调用 readExternal()
方法,如userName=(String) in.readObject()
,根据序列顺序挨个读取进行反序列,并自动封装成对象返回。
可以看出来Externalizable形式的序列化会更灵活一些,可以自己定义哪些字段需要序列化,和transient的功能有些类似。
代码示例
代码中有两种实现方式,第一种的测试代码被注释了。
public class SerializationPractice { public void serializableTest() { // Worker worker = new Worker(); Worker1 worker = new Worker1(); worker.setAge(30); worker.setName("gary"); worker.setHeight(170); System.out.println(worker); try (ObjectOutputStream objectOutputStream = new ObjectOutputStream( new FileOutputStream("/Users/gary/Documents/serializeTest.txt"))) { objectOutputStream.writeObject(worker); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void deserializeTest() { try (ObjectInputStream objectInputStream = new ObjectInputStream( new FileInputStream("/Users/gary/Documents/serializeTest.txt"))) { // Worker worker = (Worker) objectInputStream.readObject(); Worker1 worker = (Worker1) objectInputStream.readObject(); System.out.println(worker); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } public static void main(String[] args) { SerializationPractice practice = new SerializationPractice(); //序列化 practice.serializableTest(); //反序列化 //practice.deserializeTest(); }}class Worker implements Serializable { private static final long serialVersionUID = 2L; private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "name=" + name + " ,age=" + age; }}class Worker1 implements Externalizable { private static final long serialVersionUID = 1L; private String name; private int age; private int height; public Worker1() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public int getHeight() { return height; } public void setHeight(int height) { this.height = height; } @Override public String toString() { return "name=" + name + ",age=" + age + ",height=" + height; } @Override public void writeExternal(ObjectOutput objectOutput) { try { objectOutput.writeObject(name); objectOutput.writeInt(age); objectOutput.writeInt(height); } catch (IOException e) { e.printStackTrace(); } } @Override public void readExternal(ObjectInput objectInput) { try { name = (String) objectInput.readObject(); age = objectInput.readInt(); height = objectInput.readInt(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }}
实现接口Externalizable的序列化时要注意一下情况:
writeExternal方法中没序列化的属性,反序列化后得到的是属性类型的默认值,和 transient 作用类似。
实现接口Externalizable的类要提供无参数的构造函数,否则会报下面的错误
java.io.InvalidClassException: javabase.serialization.Worker1; no valid constructor
在使用Externalizable进行序列化的时候,在读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。所以,实现Externalizable接口的类必须要提供一个public的无参的构造器。
序列化ID
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID
)。
序列化时 serialVersionUID=1L
,然后反序列化是修改Worker类的 serialVersionUID=2L
,就会报下面的错误。
java.io.InvalidClassException: javabase.serialization.Worker; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
总结
- 如果一个类想被序列化,需要实现Serializable接口或Externalizable接口。否则将抛出NotSerializableException异常,这是因为,在序列化操作过程中会对类型进行检查,要求被序列化的类必须属于Enum、Array和Serializable类型其中的任何一种。
- 在变量声明前加上该关键字,可以阻止该变量被序列化到文件中。
- 在类中增加writeObject 和 readObject 方法可以实现自定义序列化策略
- 序列化并不保存静态变量。
参考资料
Java对象的序列化与反序列化
- Java——transient and 序列化
- java transient 序列化
- java学习——序列化与 Transient 关键字
- java学习——序列化与 Transient 关键字
- java序列化和transient
- java 序列化 serialVersionUID transient
- Java序列化之transient
- Java序列化 transient关键字
- java序列化之transient
- java序列化之transient
- java 序列化和transient的用法
- Java序列化与transient关键字
- java关键字transient与序列化相关
- java(十四):transient与序列化
- Java 对象序列化和transient 作用
- Java volatile and transient
- transient与序列化
- transient与序列化
- POJ 2182 Lost Cows (树状数组+二分 / 线段树 / 枚举)
- windows下在一台电脑上配置多个git账号
- javascript input标签 控制只允许输入数字代码
- H5同层播放器接入的规范
- How many items that are double some other item
- Java——transient and 序列化
- CSS 三种引入方式
- 简单数学
- Linux基础-Centos
- warpAffine函数解析
- 记录一次elasticsearch连接问题
- 啊哈算法总结之第一章——排序
- linux命令——ps和netstat
- 影像管理技术——原始影像建库入库