【零碎JAVA】java序列化

来源:互联网 发布:发短信软件手机软件 编辑:程序博客网 时间:2024/04/29 18:28

在学习javaIO技术的时候,我们能够在java.io包中看到有ObjectInputStream,ObjectOutputStream两个类,从他们名字的结构上我们不难发现,他们分别是InputStream,OutputStream的子类,他们的功能是对对象的读写。查阅java API,文档上是这么描述的:

        ObjectInputStream:ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化。

        ObjectOutputStream:ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。

通俗一点讲,ObjectOutputStream可以将对象写入OutputStream流中(比如文件,已达到对象的持久化存储),我们知道,java中对象存储在对内存中,因此,ObjectOutputStream是将对内存中的对象写入OutputStream流中。相反的,ObjectInputStream的作用是可以将对应的OutputStream流中的数据重新加载进内存。

 

 

Serializable

        自习查阅ObjectInputStream,ObjectOutputStream的api文档,里面都讲到了这么一句比较类似的话,就是只有支持 java.io.Serializable 或 java.io.Externalizable 接口的对象才能进行相关的操作,我们点击查看一下Serializable,他没有提供任何构造方法,以及成员函数,意思就是实现Serializable接口,我们无序实现任何Serializable中的方法。实际上,实现Serializable接口只是对该类进行了一次标记,标记这个类是可以被序列化的。

 

 

ObjectOutputStream 内存对象写入文件

        下面,我们看一下如何使用ObjectOutputStream,举一个简单的例子,讲堆内存中的对象写入文件,达到一个数据持久化的功能。

        首先,我们创建一个Person类,我们试图将这个Person的类对象写入文件。这个Person类必须实现Serializable接口。

import java.io.*;class Person implements Serializable{public String name;public int age;public Person(String name, int age){this.name = name;this.age = age;}public String toString(){return this.name + ":" + this.age;}}

        我们写一个对象读写的测试类,这个测试类另起一个文件,不要将他与Person写在同一个文件,将对象写入本地文件的关键代码如下,异常的捕获,处理就不写出来了:

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"));oos.writeObject(new Person("zhangsan", 28));oos.close();

        此处,我将这个对象写入本地的object.txt文件中,编译执行代码,我们会发现object.txt文件产生了,打开后可以看到一串看不懂的字符,说明写入成功了。

 

 

ObjectOutputStream 将本地文件中的对象重新加载进内存

        下面,我们看一下如何将本地文件中对象加载进内存,以供程序使用,他的关键代码如下所示,异常的捕获处理就不写出来了:

ObjectInputStream ois = new ObjectInputStream(new FileInputStream("object.txt"));Person p = (Person)ois.readObject();System.out.println(p);

        编译代码,执行,我们就能够看到Person对象的内容在控制台打印出来了。


 

序列化的一些问题

        问题1.如果对象已经存储与本地文件,但是后期修改了对象所属类的结构,再次使用ObjectInuputStream会有什么问题?

            我们将Person类中的name属性设置成private,然后编译Person重新生成.class文件,然后执行本地对象的读操作(此时Object.txt存放的是之前Person的对象,现在生成了新的Person.class文件,两者肯定是有区别的),我们会发现如下错误:

Exception in thread "main" java.io.InvalidClassException: Person; local class incompatible: stream classdesc serialVersionUID = -1945702287438740193, local class serialVersionUID = -7312174078679069023

            他的意思是说本地Person字节码的serialVersionUID与流中的(即Object.txt)serialVersionUID不一致。这说明ObjectInputStream,ObjectOutputStream对对象进行读写的时候会判断.class中的serialVersionUID与流中的serialVersionUID是否一致,若不一致说明不匹配,就会报以上错误,提高了程序的可靠性。我们可以将[ANY-ACCESS-MODIFIER] static final long serialVersionUID属性作为类属性写死。

 

        问题2.为什么static声明的属性不能被序列化?

            我们修改Person类,添加静态的addr属性,修改构造方法,以及toString方法

import java.io.*;class Person implements Serializable{public  String name;public int age;public static String addr = "beidajie112";public Person(String name, int age, String addr){this.name = name;this.age = age;this.addr = addr;}public String toString(){return this.name + ":" + this.age + ":" + this.addr;}}

            重新写入文件

<span style="color:#ff0000;">oos</span>.writeObject(new Person("zhangsan", 28, "changanjie123"));

            执行读取文件,并在控制台输出,我们发现输出的地址栏是“beidajie112”,而不是我们后来的“changanjie123”,说明addr这个属性并没有存入文件,他获取的是默认的addr值,因为静态对象并不存放在对内存中,而ObjectOutputStream是将对内存中的对象序列化,所以static的属性不能被序列化!

            如果我们不想让我们的非静态成员被序列化,我们可以给该属性加上transient的关键字,来达到这个效果。

 

 

 

 

 

0 0
原创粉丝点击