详解java序列化

上传人:ba****u6 文档编号:168272557 上传时间:2022-11-08 格式:DOCX 页数:18 大小:67.48KB
收藏 版权申诉 举报 下载
详解java序列化_第1页
第1页 / 共18页
详解java序列化_第2页
第2页 / 共18页
详解java序列化_第3页
第3页 / 共18页
资源描述:

《详解java序列化》由会员分享,可在线阅读,更多相关《详解java序列化(18页珍藏版)》请在装配图网上搜索。

1、我们可以通过序列化来保存一个对象的状态(实例变量)到文件中,也可以从 这个格式化的文件中很容易地读取对象的状态从而可以恢复我们保存的对象。用来实现序列化的类都在java.io包中,我们常用的类或接口有: ObjectOutputStream:提供序列化对象并把其写入流的方法ObjectInputStream :读取流并反序列化对象Serializable :一个对象想要被序列化,那么它的类就要实现此接口下面我们先通过一个简单的例子演示一起序列他反序列化的过程Book.javapackage kevin.seria;import java.io.Serializable;public class

2、 Book implements Serializable(private int isbn;public Book(int isbn) (super();this.isbn = isbn;public int getIsbn() (return isbn;public void setIsbn(int isbn) (this.isbn = isbn;Overridepublic String toString() (return Book isbn= + isbn + ;Student.javapackage kevin.seria;import java.io.Serializable;p

3、ublic class Student implements Serializable ( private Book book; private String name;public Student(Book book, String name) (super();this.book = book;this.name = name; public Book getBook() (return book; public void setBook(Book book) ( this.book = book;public String getName() ( return name;public v

4、oid setName(String name) ( this .name = name;Overridepublic String toString() (return Student book= + book + , name= + name + ; Simulator.javapackage kevin.seria;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.IOException;import java

5、.io.ObjectInputStream;import java.io.ObjectOutputStream;public class Simulator (public static void main(String args) ( new Simulator().go();private void go()(Student student = new Student(new Book(2011),kevin);try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(seria);out.write

6、Object(student); / System.out.println(object has been written.); out.close(); catch (FileNotFoundException e) ( e.printStackTrace(); catch (IOException e) ( e.printStackTrace();try(ObjectInputStream in = new ObjectInputStream(new FileInputStream(seria);Student studentRead = (Student) in.readObject()

7、; System.out.println(object read here:); System.out.println(studentRead);catch(FileNotFoundException e)(e.printStackTrace(); catch (lOException e) (e.printStackTrace(); catch (ClassNotFoundException e) (/ TODO Auto-generated catch block e.printStackTrace();这个程序运行的结果如下:Et HroDlems Javadoc 国 Ueclarati

8、on M Console 曷1=:termin ated i mulaiior Java Application D:PIatformavajdkbinj avaw.exe (2011-B-LS. object 立己吕 been written.object read nere:Stade nt book=3ook z_sbn=20H f naiae=kevn我们可以看到,读取到的对象与保存的对象状态一样。这里有几点需要说明一下:1、基本类型的数据可以直接序列化2、对象要被序列化,它的类必须要实现Serializable接口;如果一个类中有弓I用类型的实例变量,这个弓I用类型也要实现Seria

9、lizable接口。比如 上面的例子中,Student类中有一个Book类型的实例就是,要想让 Student的对象成功序列化,那么Book也必须要实现Serializable接口。3、我们看这个语句:ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(seria);我们知道FileOutputStream类有一个带有两个参数的重载Constructor FileOutputStream(String,boolean),其第二个参数如果 为true且String代表的文件存在,那么将把新的内容写到原来文件的

10、末尾而非重写这个文件,这里我们不能用这个版本的构造函数,也就 是说我们必须重写这个文件,否则在读取这个文件反序列化的过程中 就会抛出异常,导致只有我们第一次写到这个文件中的对象可以被反 序列化,之后程序就会出错。下面的问题是如果我们上面用到的Book类没有实现Serializable接口,但是我们还想 序列化Student类的对象,怎么办。Java为我们提供了 transient这个关键字。如果一个变量被声明成transient,那么在 序列化的过程中,这个变量是会被无视的。我们还是通过对上面的代码进行小的修改 来说明这个问题。新的Book类不实现Serializable接口package k

11、evin.seria;public class Book(private int isbn;public Book(int isbn) (super();this.isbn = isbn;public int getIsbn() (return isbn;public void setIsbn(int isbn) (this.isbn = isbn;Overridepublic String toString() (return Book isbn= + isbn + ;因为我们要序列化Student类的对象,所以我们必须实现Serializable接口,然而Book 是Student的一个实

12、例变量,它的类没有实现Serializable接口,所以为了顺序完成序 列化,我们把这个实例变量声明为transient以在序列化的过程中跳过它。package kevin.seria;import java.io.Serializable;public class Student implements Serializable ( private transient Book book; private String name;public Student(Book book, String name) (super();this.book = book;this.name = name;

13、public Book getBook() (return book; public void setBook(Book book) ( this.book = book;public String getName() ( return name;public void setName(String name) ( this .name = name;Overridepublic String toString() (return Student book= + book + , name= + name + ; Simulator.java和上面的一样,我们看一下运行结果:, Pr&blem

14、s Javad&c 1. Declaration 目 Conwls 牌敝 | 黄terminated Simulator Java Application D:Platfcrrmsjavajclkbinjswaw.exe 2011-3-18 Jz- abj&ct ?ias been written.abj ect read here:Student iaofc=Qullf nair.e=k;evin可以看到,student对象被成功的序列化了。因为序列化过程中跳过了 Book实例,所 以当恢复对象状态的时候,它被赋予了默认值null,这也就意味着我们不能使用它。 那如果Book类没有实现Ser

15、ializable接口,但我们还想对它的状态进行保存,这可以 实现吗?答案是肯定的,到底如何肯定,请听小弟我慢慢道来。Java针对这种情况有一种特殊的机制一组私有(回调)方法(这个我们马上在代 码中看到),可以在要被序列化的类中实现它们,在序列化和的序列化的过程中它们 会被自动调用。所以在这组方法中我们可以调用 ObjectOutputStream/ObjectInputStream的一些有用方法来实现对象状态的保存。下 面还是通过例子来说明:Book类和Simulator类都不变,我们来看一下新的Student类:package kevin.seria;import java.io.IOEx

16、ception;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class Student implements Serializable ( private transient Book book;private String name;public Student(Book book, String name) (super();this.book = book;this.name = name;public Book getBook(

17、) ( return book;public void setBook(Book book) ( this.book = book;public String getName() ( return name;public void setName(String name) ( this .name = name;下面这两个方法就是那组特殊的私有方法,它们会在序列化、反序列化的过程中被 自动调用我们必须保证方法的签名和下面的两个方法完全相同/这个方法会在序列化的过程中被调用private void writeObject(ObjectOutputStream out)(try (out.defa

18、ultWriteObject(); /这个方法会把这当前中非静态 变量和非transient变量写到流中/在这里我们就 把name写到了流中。因为我们要保存Book的状态,所以我们还要想办法把其状态写入流 中out.writeInt(book.getIsbn();/ObjectOutputStream中 提供了写基本类型数据的方法/out.close() ;/注意,这句千万不能有,否刚将直接导致写入失 败 catch (IOException e) ( e.printStackTrace(); /这个方法会在反序列化的过程中被调用private void readObject(ObjectIn

19、putStream in)(try (in.defaultReadObject(); /和defaultWriteObject() 方法相对应,默认的反序列化方法,会从流中读取/非静态变量和非 transient 变量int isbn = in.readInt(); /用这个方法来读取一 int型值, 这里我们是读取书号book = new Book(isbn); /这里我们就通过读取的 保存的状 态构造了一和原来一样的Book对象/in.close() ;同样的这句也不能有 catch (lOException e) (e.printStackTrace(); catch (ClassNot

20、FoundException e) (e.printStackTrace();Overridepublic String toString() (return Student book= + book + , name= + name + ;i Problems Javadoc 凰 Declaration好,看下程序运行的结果,我们这次期望的是Book的状态得到了保存,ok ,check it outConsole 3 Simulator Java Application D Pl a irfo rm a vaj d bi nj a v aw. e object has been writte

21、n.object read here:Student book=BQok i5bn=2CiH f nair.e=kevin OH YES !正如预料的一样,我们成功了。呵呵。要注意的点我在代码的注释中有说 明,请好好看下代码。还有一点我在代码中没写出来,就是一定要注意写入和读取的顺序一定要对应。像上 面如果你是先写基本类型数据的话,那在读取的时候也一定要先读取基本类型的数据, 这个原因我想大家都清楚,文件是有position的。最后,还有两个问题:1、如果一个类没有实现Serializable接口,但是它的基类实现了,这个类可不可 以序列化?2、和上面相反,如果一个类实现了 Serializa

22、ble接口,但是它的父类没有实现, 这个类可不可以序列化?第1个问题:一个类实现了某接口,那么它的所有子类都间接实现了此接口,所以它 可以被序列化。第2个问题:Object是每个类的超类,但是它没有实现Serializable接口,但是我们照 样在序列化对象,所以说明一个类要序列化,它的父类不一定要实现Serializable接口。 但是在父类中定义的状态能被正确的保存以及读取吗?这个我将在下一篇文章中用一 个例子来说明(马上就更新),请列位看官多多关注,呵呵。还有一点,序列化保存对象的状态,而静态(static)变量不是对象的状态,所以它们 不会被序列化。好的,继续为大家带来上一篇文章详解j

23、ava序列化(一) 中最后第 2 个问题的解答。第2个问题:Object是每个类的超类,但是它没有实现Serializable接口,但是我们照 样在序列化对象,所以说明一个类要序列化,它的父类不一定要实现Serializable接口。但是在父类中定义的状态能被正确的保存以及读取吗?我们还是围绕上面用过的那些类来做一些修改,看下面这个例子。Book.java这个类和上次的一样,不实现Serializable接口 package kevin.seria;public class Book(private int isbn;public Book(int isbn) (super();this.is

24、bn = isbn;public int getIsbn() ( return isbn;public void setIsbn(int isbn) ( this.isbn = isbn;Overridepublic String toString() ( return Book isbn= + isbn + ;这里我们新定义一个类NewBook继承Book类,并且实现Serializable接口,下面看定 义package kevin.seria;import java.io.Serializable;public class NewBook extends Book implements

25、Serializable( private String author;public NewBook(int isbn,String author) ( super(isbn); this.author = author; public String getAuthor() ( return author;public void setAuthor(String author) ( this.author = author;Overridepublic String toString() (return NewBook author= + author + super.toString()+

26、;然后,我们把Student类中Book类型的实例变量修改成NewBook类型,修改后的Student 类package kevin.seria;import java.io.Serializable;public class Student implements Serializable (private NewBook book;private String name;public Student(NewBook book, String name) (super();this.book = book;this .name = name;public NewBook getBook() (

27、return book;public void setBook(NewBook book) (this.book = book;public String getName() (return name;public void setName(String name) ( this.name = name;Overridepublic String toString() (return Student book= + book + , name= + name + ; Simulator 类的内容不变,不过我还是把代码贴出来,可能有的童鞋并没有看上一 篇文章:package kevin.seri

28、a;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 Simulator (public static void main(String args) ( new Simulator().go();private void go()(St

29、udent student = new Student(new NewBook(2011,moree),kevin);try (ObjectOutputStream out = newObjectOutputStream(new FileOutputStream(seria);out.writeObject(student); /System.out .println(object has been written.); out.close(); catch (FileNotFoundException e) (e.printStackTrace(); catch (IOException e

30、) (e.printStackTrace();try(ObjectInputStream in = new ObjectInputStream(new FileInputStream(seria);Student studentRead = (Student) in.readObject();System.out.println(object read here:);System.out.println(studentRead);catch(FileNotFoundException e)(e.printStackTrace(); catch (IOException e) (e.printS

31、tackTrace(); catch (ClassNotFoundException e) (/ TODO Auto-generated catch block e.printStackTrace();好,我们运行这个程序,看下输出结果:从结果可以看出,对象写成功了,但在读取的过程中出现了问题,具体的异常原因: no valid constructor,即没有有效的构造函数,那么到底是哪个类没有有效的构造函 数呢,到底需要一个什么样的构造函数呢?对于这种情况,即父类没有实现Serializable接口时,但其子类实现了此接口,那么 这个子类是可以序列化的,但是在反序列化的过程中会调用父类的无参

32、构造函数, 上面异常抛出的原因就是因为我们在Book类中没有一个无参的构造函数。好,那我们 下面就为Book类添加一个默认的构造函数。package kevin.seria;public class Book(private int isbn;public Book()(isbn=888;System.out .println(Book class no-arg constructor invoked.);public Book(int isbn) (super();this.isbn = isbn;public int getIsbn() (return isbn; public void

33、setIsbn(int isbn) ( this.isbn = isbn;Overridepublic String toString() (return Book isbn= + isbn + ; 再来执行一次程序,看输出结果如何:Eti PrQblem&| Javadocl?ecl a ration 导匚 dhs启 亮 Simulator Java Application D Pl a tfo-rm sj a vaj d k b i nj a va w. exe (2011-8-18 ptject nas teen wiitten.Eook class no-aig constiactoi

34、 invoked.abject lead ?ieTe :Etudent kook=NewBocik a.wthoTrr.oieeBook lslrL=B3B f najae=kevin我们可以看到在反序列化的过程中调用了 Book类的无参构造执行一个初始化的操作。 好,我们总结一下:如果父类没有实现Serializable接口,但其子类实现了此接口, 那么这个子类是可以序列化的,但是在反序列化的过程中会调用父类的无参构造函 数,所以在其直接父类(注意是直接父类)中必须有一个无参的构造函数。好,对于第2个问题的讨论就到这里,接下来我们提出第3个问题:如果将一个对象写入某文件(比如是a),那么之后

35、对这个对象进行一些修改,然后 把修改的对象再写入文件a,那么文件a中会包含该对象的两个版本吗?至于包不包含,我们代码见分晓:我们修改Simulator类如下:package kevin.seria;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

36、class Simulator (public static void main(String args) ( new Simulator().go();private void go()(try (ObjectOutputStream out = newObjectOutputStream(new FileOutputStream(seria);Student student1 = new Student(newNewBook(2011,moree),kevin);out.writeObject(student1); /student1.setName(Jordan);out.writeOb

37、ject(student1);student1.setName(Paul);out.writeObject(student1);System.out .println(object has been written.);out.close(); catch (FileNotFoundException e) ( e.printStackTrace(); catch (IOException e) ( e.printStackTrace();try(ObjectInputStream in = new ObjectInputStream(new FileInputStream(seria);St

38、udent s1 = (Student)in.readObject();Student s2 = (Student)in.readObject();Student s3 = (Student)in.readObject();System.out.println(Objects read here: );System.out.println(Student1s name: +s1.getName();System.out.println(Student2s name: +s2.getName();System.out.println(Student3s name: +s3.getName();c

39、atch(FileNotFoundException e)(e.printStackTrace(); catch (IOException e) (e.printStackTrace(); catch (ClassNotFoundException e) (/ TODO Auto-generated catch block e.printStackTrace();我们希望输出三个人的名字:kevin,Jordan,Paul,那看一下它到底是不是如我们所愿呢:诙 Frciblems | 四 Javadoc | LJeclaration 住 Lonsole 尊cterminaie-d Si mul

40、ato-r Java Application D:Pl atforrmsjavajdktject n己5 keen writtenBoot class no-arg constraccoi invoked.Objects read j-iere:St uideLtl1 s name : kevinStuidentZ s name: kevz_|Studentsb name: kevin事与愿违啊,它输出了三个kevin,这证明我们对student名字的修改并没有被写入。 原因是序列化输出过程跟踪写入流的对象,试图将同一个对象写入流时,不会导致该 对象被复制,而只是将一个句柄写入流,该句柄指向流

41、中相同对象的第一个对象出现 的位置。那我们如何来避免这种情况,让它输出三个人名呢,方法是在writeObject()之前调用 out.reset()方法,这个方法的作用是清除流中保存的写入对象的记录。我们还是通过代 码来看下效果。try (ObjectOutputStream out = newObjectOutputStream(new FileOutputStream(seria);Student studentl = new Student(newNewBook(2011,moree),kevin);out.writeObject(student1); /out.reset();student1.setName(Jordan);out.writeObject(student1);out.reset();student1.setName(Paul);out.writeObject(student1);System.out .println(object has been written.); out.close(); catch (FileNotFoundException e) (这样修改以后就会输出我们期望的结果了。好,第3个问题的讨论到此为止,如果想深入了解java序列化,可以看下专门讨论这方面的 书。8/18/2011 by Kevin (End)

展开阅读全文
温馨提示:
1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
2: 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
3.本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
关于我们 - 网站声明 - 网站地图 - 资源地图 - 友情链接 - 网站客服 - 联系我们

copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!