博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
day19Java-其它IO-ObjectIn(Out)putStream-(反)序列化流
阅读量:267 次
发布时间:2019-03-01

本文共 6234 字,大约阅读时间需要 20 分钟。

博客名称

文章目录

ObjectIn(Out)putStream-(反)序列化流

java.io.InputStream 继承者 java.io.ObjectInputStream

java.io.OutputStream 继承者 java.io.ObjectOutputStream

序列化流:把对象按照流一样的方式存入文本文件或者在网络中传输。对象 -- 流数据(ObjectOutputStream)反序列化流:把文本文件中的流对象数据或者网络中的流对象数据还原成对象。流数据 -- 对象(ObjectInputStream)

ObjectOutputStream-序列化流

将Person转为流的时候出现异常:NotSerializableException: com.ginger.demo01.Person

类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
该接口居然没有任何方法,类似于这种没有方法的接口被称为标记接口。

原因是:如果一个对象,转化为一个流(进行网络传输)必须要实现Serializable标记接口,在这里Person没有实现所以报改错,所以得加上

代码演示

public class ObjectInputStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//写 writer(); } public static void writer() throws IOException {
//创建序列化流对象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt")); //创建Perion对象 Person p = new Person("格雷福斯", 40); //对象--流数据--oos.txt oos.writeObject(p); oos.close(); }}

实体类

//实现Serializable接口就可以进行网络传输public class Person implements Serializable{
private String name; private int age; public Person(String name, int age) {
this.name = name; this.age = 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; }}

结果:没实现接口之前

Exception in thread "main" java.io.NotSerializableException: com.ginger.demo01.Person	at java.base/java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1185)	at java.base/java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:349)	at com.ginger.demo01.ObjectInputStreamDemo.writer(ObjectInputStreamDemo.java:24)	at com.ginger.demo01.ObjectInputStreamDemo.main(ObjectInputStreamDemo.java:8)

ObjectInputStream-反序列化流

在第一次读取的时候没有报错,直接输出Person对象的时候,打印的是地址值,看得不是很方便,所以我在Person重写了toString方法此时报错了。InvalidClassException: com.ginger.demo01.Person; local class incompatible: stream classdesc serialVersionUID = 311183030272692197, local class serialVersionUID = 6499259360078010285为什么第一次读取不出现异常,在Person重写toString方法的时候在读取,就出现上述异常?	原因:Person类实现了序列化接口Serializable,那么它本身也因该有一个标记值。	假设该标记值为1000。		Person.class -- 序列化id=1000	(把java文件编译成class文件)		writer数据 -- oos.txt  -- 序列化id该是=1000		read数据 -- oos.txt -- 反序列化id也是=1000		所以我第一次读取的时候没有抛出异常		因为输出的是地址值,重写Person的toString方法,也正是因为修改了Person方法。		Person.class -- 此时序列化id=2000	(把java文件重新编译成class文件)		writer数据 -- oos.txt -- 因为还是以前的文件,序列化id就是=1000 (此时的writer方法我已经注释了,没有重新写到文件)		read数据 -- oos.txt -- 所以读取的也还是以前的文件,序列化就是=1000出现该异常要怎么解决?	修改Person过后,重新写文件,重新读文件。(这样有一个问题,就是以前读的数据被覆盖了?)		在实际开发中,可能还需要使用以前写过的数据,不能重新写入。怎么办呢?		通过异常信息可以看出来,报错原因是因为id值不匹配,修改Perons类后,没有重新写数据,表示这里读取的数据就是以前的,然后把文件中以前的Person的序列化id和现在Person序列化id做比较发现不一样,所以报错。		如果我有办法,让这个id值在java文件中是一个固定的值,这样,在修改java文件的时候,这个id值就不会发生改变了。		怎么获取到这个ID值呢?		eclipse:实现序列化接口的时候会出现一个黄色警告线,点击提示中的两个其中一个即可。		在IDEA里面需要安装一个插件,这个在网上找就可以了。安装好后使用快捷键Alt+insert就可以了,自动生成。					private static final long serialVersionUID = 6499259360078010285L;		要知道的是:		序列化id:private static final long serialVersionUID = 6499259360078010285L;		产生这个值以后,我们对类进行任何改动,它读取以前的数据是没有问题的。(读取还是以前的信息,不是改变过后的。)注意:		我一个类中可能有很多的成员变量,有些我不想进行序列化。请问该怎么办呢?		使用transient关键字声明不需要序列化的成员变量

代码演示

public class ObjectInputStreamDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
//写 //writer(); //读 reader(); } public static void reader() throws IOException, ClassNotFoundException {
//创建反序列化流对象 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("oos.txt")); //oos.txt--流数据--对象 Object p = ois.readObject();// System.out.println(p); } public static void writer() throws IOException {
//创建序列化流对象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt")); //创建Perion对象 Person p = new Person("格雷福斯", 40,"100"); //对象--流数据--oos.txt oos.writeObject(p); oos.close(); }}

实体类

public class Person implements Serializable {
//自动生成序列化id private static final long serialVersionUID = 6499259360078010285L; private String name; private int age; private String chinese; public String getChinese() {
return chinese; } public void setChinese(String chinese) {
this.chinese = chinese; } public Person(String name, int age, String chinese) {
this.name = name; this.age = age; this.chinese = chinese; } 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 "Person{" + "name='" + name + '\'' + ", age=" + age + ", chinese='" + chinese + '\'' + '}'; }}

结果:

Person{
name='格雷福斯', age=40, chinese='100'}

修改实体类,chinese这个字段我不想被序列化,重新写读。

public class Person implements Serializable {
//自动生成序列化id private static final long serialVersionUID = 6499259360078010285L; private String name; private int age; //transient:chinese我不想被序列化 private transient String chinese; public String getChinese() {
return chinese; } public void setChinese(String chinese) {
this.chinese = chinese; } public Person(String name, int age, String chinese) {
this.name = name; this.age = age; this.chinese = chinese; } 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 "Person{" + "name='" + name + '\'' + ", age=" + age + ", chinese='" + chinese + '\'' + '}'; }}

结果:从结果看到chinese值已经看不到了

Person{
name='格雷福斯', age=40, chinese='null'}

转载地址:http://hlya.baihongyu.com/

你可能感兴趣的文章