java序列化.docx
- 文档编号:9968430
- 上传时间:2023-05-22
- 格式:DOCX
- 页数:24
- 大小:29.55KB
java序列化.docx
《java序列化.docx》由会员分享,可在线阅读,更多相关《java序列化.docx(24页珍藏版)》请在冰点文库上搜索。
java序列化
所谓java对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再生成相同状态的对象!
对象序列化是对象持久化的一种实现方法,它是将一个对象的属性和方法转化为一种序列化的格式以用于存储和传输,反序列化就是根据这些保存的信息重建对象的过程。
Java对象序列化机制一般来讲有两种用途:
Java的JavaBeans:
Bean的状态信息通常是在设计时配置的,Bean的状态信息必须被存起来,以便当程序运行时能恢复这些状态信息,这需要将对象的状态保存到文件中,而后能够通过读入对象状态来重新构造对象,恢复程序状态。
RMI允许象在本机上一样操作远程机器上的对象;或使用套接字在网络上传送对象的程序来说,这些都是需要实现serializaiton机制的。
我们通过让类实现Java.io.Serializable接口可以将类序列化。
这个接口是一个制造者(marker)接口。
也就是说,对于要实现它的类来说,该接口不需要实现任何方法。
它主要用来通知Java虚拟机(JVM),需要将一个对象序列化。
对于这个,有几点我们需要明确:
并非所有类都可以序列化,在cmd下,我们输入serialverJ.Socket,可以得到socket是否可序列化的信息,实际上socket是不可序列化的。
Java有很多基础类已经实现了serializable接口,比如string,vector等。
但是比如hashtable就没有实现serializable接口。
将对象读出或者写入流的主要类有两个:
ObjectOutputStream与ObjectInputStream.ObjectOutputStream提供用来将对象写入输出流的writeObject方法,ObjectInputStream提供从输入流中读出对象的readObject方法。
西安达内java培训讲师表示,使用这些方法的对象必须已经被序列化的。
也就是说,必须已经实现Serializable接口。
如果你想writeobject一个hashtable对象,那么,会得到一个异常。
序列化的过程就是对象写入字节流和从字节流中读取对象。
将对象状态转换成字节流之后,可以用Java.io包中的各种字节流类将其保存到文件中,管道到另一线程中或通过网络连接将对象数据发送到另一主机。
西安达内java培训讲师表示,对象序列化功能非常简单、强大,在RMI、Socket、JMS、EJB都有应用。
对象序列化问题在网络编程中并不是最激动人心的课题,但却相当重要,具有许多实用意义。
对象序列化可以实现分布式对象。
主要应用例如:
RMI要利用对象序列化运行远程主机上的服务,就像在本地机上运行对象时一样。
Java对象序列化不仅保留一个对象的数据,而且递归保存对象引用的每个对象的数据。
可以将整个对象层次写入字节流中,可以保存在文件中或在网络连接上传递。
利用对象序列化可以进行对象的“深复制”,即复制对象本身及引用的对象本身。
序列化一个对象可能得到整个对象序列。
Java序列化比较简单,通常不需要编写保存和恢复对象状态的定制代码。
实现Java.io.Serializable接口的类对象可以转换成字节流或从字节流恢复,不需要在类中增加任何代码。
只有极少数情况下才需要定制代码保存或恢复对象状态。
西安达内java培训讲师提醒:
不是每个类都可序列化,有些类是不能序列化的,例如涉及线程的类与特定JVM有非常复杂的关系。
序列化机制:
序列化分为两大部分:
序列化和反序列化。
序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。
反序列化就是打开字节流并重构对象。
对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。
恢复数据要求有恢复数据的对象实例。
ObjectOutputStream中的序列化过程与字节流连接,包括对象类型和版本信息。
反序列化时,JVM用头信息生成对象实例,然后将对象字节流中的数据复制到对象数据成员中。
下面我们分两大部分来阐述:
处理对象流:
(序列化过程和反序列化过程)
Java.io包有两个序列化对象的类。
ObjectOutputStream负责将对象写入字节流,ObjectInputStream从字节流重构对象。
我们先了解ObjectOutputStream类吧。
ObjectOutputStream类扩展DataOutput接口。
writeObject()方法是最重要的方法,用于对象序列化。
如果对象包含其他对象的引用,则writeObject()方法递归序列化这些对象。
每个ObjectOutputStream维护序列化的对象引用表,防止发送同一对象的多个拷贝。
(这点很重要)由于writeObject()可以序列化整组交叉引用的对象,因此同一ObjectOutputStream实例可能不小心被请求序列化同一对象。
这时,进行反引用序列化,而不是再次写入对象字节流。
定制序列化过程:
序列化通常可以自动完成,但有时可能要对这个过程进行控制。
java可以将类Java的serialization提供了一种持久化对象实例的机制。
当持久化对象时,可能有一个特殊的对象数据成员,我们不想用serialization机制来保存它。
为了在一个特定对象的一个域上关闭serialization,可以在这个域前加上关键字transient。
当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。
声明为serializable,但仍可手工控制声明为static或transient(
)
的数据成员。
序列化时,类的所有数据成员应可序列化除了声明为transient或static的成员。
将变量声明为transient告诉JVM我们会负责将变元序列化。
将数据成员声明为transient后,序列化过程就无法将其加进对象字节流中,没有从transient数据成员发送的数据。
后面数据反序列化时,要重建数据成员(因为它是类定义的一部分),但不包含任何数据,因为这个数据成员不向流中写入任何数据。
记住,对象流不序列化static或transient。
我们的类要用writeObject()与readObject()方法以处理这些数据成员。
使用writeObject()与readObject()方法时,还要注意按写入的顺序读取这些数据成员。
完全定制序列化过程:
如果一个类要完全负责自己的序列化,则实现Externalizable接口而不是Serializable接口。
Externalizable接口定义包括两个方法writeExternal()与readExternal()。
利用这些方法可以控制对象数据成员如何写入字节流.类实现Externalizable时,头写入对象流中,然后类完全负责序列化和恢复数据成员,除了头以外,根本没有自动序列化。
这里要注意了。
声明类实现Externalizable接口会有重大的安全风险。
writeExternal()与readExternal()方法声明为public,恶意类可以用这些方法读取和写入对象数据。
如果对象包含敏感信息,则要格外小心。
这包括使用安全套接或加密整个字节流。
到此为至,我们学习了序列化的基础部分知识。
我们可以通过序列化来保存一个对象的状态(实例变量)到文件中,也可以从这个格式化的文件中很容易地读取对象的状态从而可以恢复我们保存的对象。
用来实现序列化的类都在java.io包中,我们常用的类或接口有:
ObjectOutputStream:
提供序列化对象并把其写入流的方法
ObjectInputStream:
读取流并反序列化对象
Serializable:
一个对象想要被序列化,那么它的类就要实现此接口
下面我们先通过一个简单的例子演示一起序列化/反序列化的过程
Book.java
[java] viewplaincopy
1.package kevin.seria;
2.
3.import java.io.Serializable;
4.
5.public class Book implements Serializable{
6. private int isbn;
7.
8. public Book(int isbn) {
9. super();
10. this.isbn = isbn;
11. }
12.
13. public int getIsbn() {
14. return isbn;
15. }
16.
17. public void setIsbn(int isbn) {
18. this.isbn = isbn;
19. }
20.
21. @Override
22. public String toString() {
23. return "Book [isbn=" + isbn + "]";
24. }
25.
26.
27.}
Student.java
[java] viewplaincopy
1.package kevin.seria;
2.
3.import java.io.Serializable;
4.
5.public class Student implements Serializable {
6. private Book book;
7. private String name;
8.
9. public Student(Book book, String name) {
10. super();
11. this.book = book;
12. this.name = name;
13. }
14.
15. public Book getBook() {
16. return book;
17. }
18.
19. public void setBook(Book book) {
20. this.book = book;
21. }
22.
23. public String getName() {
24. return name;
25. }
26.
27. public void setName(String name) {
28. this.name = name;
29. }
30.
31. @Override
32. public String toString() {
33. return "Student [book=" + book + ", name=" + name + "]";
34. }
35.
36.}
Simulator.java
[java] viewplaincopy
1.package kevin.seria;
2.
3.import java.io.FileInputStream;
4.import java.io.FileNotFoundException;
5.import java.io.FileOutputStream;
6.import java.io.IOException;
7.import java.io.ObjectInputStream;
8.import java.io.ObjectOutputStream;
9.
10.public class Simulator {
11. public static void main(String[] args) {
12. new Simulator().go();
13. }
14.
15. private void go(){
16. Student student = new Student(new Book(2011),"kevin");
17.
18. try {
19. ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("seria"));
20. out.writeObject(student); //
21. System.out.println("object has been written..");
22. out.close();
23. } catch (FileNotFoundException e) {
24. e.printStackTrace();
25. } catch (IOException e) {
26. e.printStackTrace();
27. }
28.
29. try{
30. ObjectInputStream in = new ObjectInputStream(new FileInputStream("seria"));
31. Student studentRead = (Student) in.readObject();
32. System.out.println("object read here:
");
33. System.out.println(studentRead);
34. }catch(FileNotFoundException e){
35. e.printStackTrace();
36. } catch (IOException e) {
37. e.printStackTrace();
38. } catch (ClassNotFoundException e) {
39. // TODO Auto-generated catch block
40. e.printStackTrace();
41. }
42. }
43.}
这个程序运行的结果如下:
我们可以看到,读取到的对象与保存的对象状态一样。
这里有几点需要说明一下:
1、 基本类型的数据可以直接序列化
2、 对象要被序列化,它的类必须要实现Serializable接口;如果一个类中有引用类型的实例变量,这个引用类型也要实现Serializable接口。
比如上面的例子中,Student类中有一个Book类型的实例就是,要想让Student的对象成功序列化,那么Book也必须要实现Serializable接口。
3、 我们看这个语句:
ObjectOutputStreamout = newObjectOutputStream(new FileOutputStream("seria"));
我们知道FileOutputStream类有一个带有两个参数的重载Constructor——FileOutputStream(String,boolean),其第二个参数如果为true且String代表的文件存在,那么将把新的内容写到原来文件的末尾而非重写这个文件,这里我们不能用这个版本的构造函数,也就是说我们必须重写这个文件,否则在读取这个文件反序列化的过程中就会抛出异常,导致只有我们第一次写到这个文件中的对象可以被反序列化,之后程序就会出错。
下面的问题是如果我们上面用到的Book类没有实现Serializable接口,但是我们还想序列化Student类的对象,怎么办。
Java为我们提供了transient这个关键字。
如果一个变量被声明成transient,那么在序列化的过程中,这个变量是会被无视的。
我们还是通过对上面的代码进行小的修改来说明这个问题。
新的Book类不实现Serializable接口
[java] viewplaincopy
1.package kevin.seria;
2.
3.public class Book{
4. private int isbn;
5.
6. public Book(int isbn) {
7. super();
8. this.isbn = isbn;
9. }
10.
11. public int getIsbn() {
12. return isbn;
13. }
14.
15. public void setIsbn(int isbn) {
16. this.isbn = isbn;
17. }
18.
19. @Override
20. public String toString() {
21. return "Book [isbn=" + isbn + "]";
22. }
23.
24.
25.}
因为我们要序列化Student类的对象,所以我们必须实现Serializable接口,然而Book是Student的一个实例变量,它的类没有实现Serializable接口,所以为了顺序完成序列化,我们把这个实例变量声明为transient以在序列化的过程中跳过它。
[java] viewplaincopy
1.package kevin.seria;
2.
3.import java.io.Serializable;
4.
5.public class Student implements Serializable {
6. private transient Book book;
7. private String name;
8.
9. public Student(Book book, String name) {
10. super();
11. this.book = book;
12. this.name = name;
13. }
14.
15. public Book getBook() {
16. return book;
17. }
18.
19. public void setBook(Book book) {
20. this.book = book;
21. }
22.
23. public String getName() {
24. return name;
25. }
26.
27. public void setName(String name) {
28. this.name = name;
29. }
30.
31. @Override
32. public String toString() {
33. return "Student [book=" + book + ", name=" + name + "]";
34. }
35.
36.}
Simulator.java和上面的一样,我们看一下运行结果:
可以看到,student对象被成功的序列化了。
因为序列化过程中跳过了Book实例,所以当恢复对象状态的时候,它被赋予了默认值null,这也就意味着我们不能使用它。
那如果Book类没有实现Serializable接口,但我们还想对它的状态进行保存,这可以实现吗?
答案是肯定的,到底如何肯定,请听小弟我慢慢道来。
。
。
Java针对这种情况有一种特殊的机制——一组私有(回调)方法(这个我们马上在代码中看到),可以在要被序列化的类中实现它们,在序列化和的序列化的过程中它们会被自动调用。
所以在这组方法中我们可以调用ObjectOutputStream/ObjectInputStream的一些有用方法来实现对象状态的保存。
下面还是通过例子来说明:
Book类和Simulator类都不变,我们来看一下新的Student类:
[java] viewplaincopy
1.package kevin.seria;
2.
3.import java.io.IOException;
4.import java.io.ObjectInputStream;
5.import java.io.ObjectOutputStream;
6.import java.io.Serializable;
7.
8.public class Student implements Serializable {
9. private transient Book book;
10. private String name;
11.
12. public Student(Book book, String name) {
13. super();
14. this.book = book;
15. this.name = name;
16. }
17.
18. public Book getBook() {
19. return book;
20. }
21.
22. public void setBook(Book boo
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- java 序列