zoukankan      html  css  js  c++  java
  • Java基础-IO流对象之序列化(ObjectOutputStream)与反序列化(ObjectInputStream)

           Java基础-IO流对象之序列化(ObjectOutputStream)与反序列化(ObjectInputStream)

                                              作者:尹正杰

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

    一.对象的序列化与反序列化

       ObjectOutputStream流用于将对象保存在磁盘中,或者通过网络传输到另一台主机上。保存在文件中的对象的二进制流可以用ObjectInputStream流在以后被还原成原来的对象。

      对象输出流的对象可以永久的保存在磁盘上,使对象可以脱离程序而存在,此过程也称为“序列化”过程,反之,将磁盘的数据加载到内存中的就称为“反序列化”过程。换句话说,对象中的数据以流的形式写入到文件中保存的过程称为写出对象,也叫对象的序列化,在文件中以流的形式将对象读取出来,读取对象的过程也叫反序列化。

      

      注意:反序列化是不走构造方法的哟!

    二.ObjectOutputStream流写对象

      类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。

      接下来我们定义一个实现Serializable类接口如下:

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note6;
     8 
     9 import java.io.Serializable;
    10 
    11 public class Person implements Serializable{
    12     private String Name;
    13     private int Age;
    14     public Person(String name, int age) {
    15         super();
    16         Name = name;
    17         Age = age;
    18     }
    19     
    20     public String getName() {
    21         return Name;
    22     }
    23     
    24     public void setName(String name) {
    25         Name = name;
    26     }
    27     
    28     public int getAge() {
    29         return Age;
    30     }
    31     
    32     public void setAge(int age) {
    33         Age = age;
    34     }
    35     
    36     @Override
    37     public String toString() {
    38         return "Person [姓名=" + Name + ",年龄=" + Age+ "]";
    39     }
    40 }
    Person.java 文件内容

      定义好需要序列化的对象之后,我们需要就来搞事情吧,看看ObjectOutputStream 到底是如何使用的,案例如下:

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note6;
     8 
     9 import java.io.File;
    10 import java.io.FileOutputStream;
    11 import java.io.IOException;
    12 import java.io.ObjectOutputStream;
    13 
    14 public class ObjectOutputStreamDemo {
    15     public static void main(String[] args) throws IOException {
    16         //创建字节输出流,封装文件
    17         File file = new File("yinzhengjie.txt");
    18         if(!file.exists()) {
    19             file.createNewFile();
    20         }
    21         FileOutputStream fos = new FileOutputStream(file);
    22         
    23         //创建写出对象的序列化流的对象,构造方法传递字节输出流
    24         ObjectOutputStream oos = new ObjectOutputStream(fos);
    25         Person p = new Person("yinzhengjie", 18);
    26         //调用序列化流的方法writeObject,写出对象。需要实例对象p具有序列化接口,否则会抛出异常对象:java.io.NotSerializableException
    27         oos.writeObject(p);
    28         //别忘了释放资源哟!
    29         oos.close();
    30     }
    31 }

    三.ObjectInputStream流读取对象

       在反序列一个文件内容的时候可能会存在java.lang.ClassNotFoundException类异常,原因是缺少反序列的字节码(*.class)文件。因此,序列化的前提是:必须有反序列化相关的字节码文件。现在我们把之前序列化的文件进行反序列操作,如下:

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note6;
     8 
     9 import java.io.File;
    10 import java.io.FileInputStream;
    11 import java.io.IOException;
    12 import java.io.ObjectInputStream;
    13 
    14 public class ObjectInputSteamDemo {
    15     public static void main(String[] args) throws IOException, ClassNotFoundException {
    16         //创建字节输入流,封装文件
    17         File file = new File("yinzhengjie.txt");
    18         FileInputStream fis = new FileInputStream(file);
    19         //创建反序列化流,构造方法中,传递字节输入流
    20         ObjectInputStream ois = new ObjectInputStream(fis);
    21         //调用反序列化流的方法"readObject()"读取对象,要注意的是反序列话的对象需要存在相应的字节码文件。否则会抛异常
    22         Object obj = ois.readObject();
    23         //记得释放资源
    24         ois.close();
    25         //查看我们的想要看的内容。
    26         System.out.println(obj);
    27     }
    28 }
    29 
    30 
    31 /*
    32 以上代码执行结果如下:
    33 Person [姓名=yinzhengjie,年龄=18]
    34 */

      注意,在序列化和反序列化过程中,序列化用的什么方法写入,我们读取的时候也应该用对应的方法去读取,打个比方,我们上面序列化一个自定义类时,用的是wirteObject()方法,读取的时候应该用对应方法读取,我们上面的案例就是用readObject方法进行读取,如果你序列化使用的wirteInt()方法,那么反序列话的时候就应该用readInt()方法哟!谨记这一点,会让你少踩很多坑的,别问我为什么这么说,因为这个坑我已经踩了你就别去踩了哈!

    四.关于序列化的面试题

    1>.静态成员变量为什么不能被序列化?

      答:序列化其实是将对象进行序列化操作,而static修饰的成员变量是属于类的,并非对象所有!因此静态修饰的成员变量无法被序列化。

    2>.瞬态关键字transient的用法?

      答:当一个类的对象需要被序列化时,某些属性不需要被反序列化,这时不需要序列化的属性可以使用关键字transient修饰,只要被transient修饰了,序列化时这个属性就不会被序列化啦!它的用法比较单一,只能用于修饰成员变量不被序列化!这样做的目的是可以节省空间,将不需要的数据不进行序列化操作。

    3>.Serializable接口有上面含义?

      答:Serializable并没有任何功能,只是一个标记性接口,就好像去菜市场买猪肉,安检人员会在猪肉上印上一个标记表示该猪肉检验合格可以食用!而在Java中用该接口只是标识该类是可以被序列化!

    4>.分析序列化中的为什么会存在序列化冲突问题?

      答:Java代码在执行之前需要经过javac命令对源代码进行编译生成字节码文件“*.class”,与此同时会给该“*.class”计算出来一个序列号(serialVersionUID),在序列化时会将该属性一并序列化到文件中。当我们对源代码再次进行编辑时,依然是需要javac命令进行编译该文件才能运行修改后的代码,此时会生成一个新的序列号(serialVersionUID)出来。这个时候当我们将序列化的文件进行反序列化操作时,首先会对比字节码文件的序列号是否一致,如果不一致,则会抛出异常:“java.io.InvalidClassException”。

    5>.为什么要自定义序列号?

      答:原因很简单,就是为了解决序列化冲突问题。我们只需要要让源代码修改前和修改后的序列号(serialVersionUID)保持一致,这样就可以正常进行序列化操作啦!我们可以看一下案例如下:

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.note6;
     8 
     9 import java.io.Serializable;
    10 
    11 public class Person implements Serializable{
    12     private String Name;
    13     public /*transient关键字在这里加,就可以阻止成员变量进行序列化啦!*/int Age;
    14     
    15     static final long serialVersionUid = 7758520L;        //类自定义序列号,编译器就不会计算序列号。
    16     
    17     public Person(String name, int age) {
    18         super();
    19         Name = name;
    20         Age = age;
    21     }
    22     
    23     public  String getName() {
    24         return Name;
    25     }
    26     
    27     public void setName(String name) {
    28         Name = name;
    29     }
    30     
    31     public int getAge() {
    32         return Age;
    33     }
    34     
    35     public void setAge(int age) {
    36         Age = age;
    37     }
    38     
    39     @Override
    40     public String toString() {
    41         return "Person [姓名=" + Name + ",年龄=" + Age+ "]";
    42     }
    43     
    44 
    45 }

    五.小试牛刀

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 package cn.org.yinzhengjie.serializable;
     7 
     8 
     9 import java.io.Serializable;
    10 import java.util.ArrayList;
    11 import java.util.List;
    12 
    13 /**
    14  * 客户类
    15  */
    16 public class Customer implements Serializable {
    17     private static final long serialVersionUID = 6327665722505706622L;
    18     private String name ;
    19     private int age ;
    20 
    21     public int getAge() {
    22         return age;
    23     }
    24 
    25     public void setAge(int age) {
    26         this.age = age;
    27     }
    28 
    29     //临时的,不参与串行化
    30     private transient List<Order> orders = new ArrayList<Order>() ;
    31 
    32     public String getName() {
    33         return name;
    34     }
    35 
    36     public void setName(String name) {
    37         this.name = name;
    38     }
    39 
    40     public List<Order> getOrders() {
    41         return orders;
    42     }
    43 
    44     public void setOrders(List<Order> orders) {
    45         this.orders = orders;
    46     }
    47 }
    Customer.java 文件内容
     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 package cn.org.yinzhengjie.serializable;
     7 
     8 
     9 import java.io.Serializable;
    10 
    11 /**
    12  * 客户类
    13  */
    14 public class Item implements Serializable {
    15     private String itemname;
    16 
    17     public String getItemname() {
    18         return itemname;
    19     }
    20 
    21     public void setItemname(String itemname) {
    22         this.itemname = itemname;
    23     }
    24 }
    Item.java 文件内容
     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 package cn.org.yinzhengjie.serializable;
     7 
     8 
     9 import java.io.Serializable;
    10 import java.util.ArrayList;
    11 import java.util.List;
    12 
    13 /**
    14  * 客户类
    15  */
    16 public class Order implements Serializable {
    17     private String orderno;
    18 
    19     private List<Item> items =new ArrayList<Item>() ;
    20 
    21     public List<Item> getItems() {
    22         return items;
    23     }
    24 
    25     public void setItems(List<Item> items) {
    26         this.items = items;
    27     }
    28 
    29     public String getOrderno() {
    30         return orderno;
    31     }
    32 
    33     public void setOrderno(String orderno) {
    34         this.orderno = orderno;
    35     }
    36 }
    Order.java 文件内容

    1>.实现浅拷贝

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 package cn.org.yinzhengjie.serializable;
     7 
     8 import org.junit.Test;
     9 
    10 public class ShallowReplicas {
    11     @Test
    12     public void testDeeplyCopy() throws Exception {
    13         Customer c = new Customer();
    14         c.setName("尹正杰");
    15 
    16         Order o1 = new Order();
    17         o1.setOrderno("0001");
    18 
    19         Order o2 = new Order();
    20         o2.setOrderno("0002");
    21 
    22         Item i1 = new Item();
    23         i1.setItemname("iphone 8 Plus");
    24 
    25         //建立关系
    26         c.getOrders().add(o1);
    27         c.getOrders().add(o2);
    28 
    29         o1.getItems().add(i1);
    30 
    31         //浅度复制
    32         Customer cc = new Customer();
    33         cc.setName(c.getName());
    34         cc.setOrders(c.getOrders());
    35 
    36         String name = cc.getName();
    37         System.out.println(name);
    38     }
    39 }

    2>.实现深度拷贝

     1 /*
     2 @author :yinzhengjie
     3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Java%E5%9F%BA%E7%A1%80/
     4 EMAIL:y1053419035@qq.com
     5 */
     6 
     7 package cn.org.yinzhengjie.serializable;
     8 
     9 import org.junit.Test;
    10 
    11 import java.io.FileInputStream;
    12 import java.io.FileOutputStream;
    13 import java.io.ObjectInputStream;
    14 import java.io.ObjectOutputStream;
    15 
    16 public class DeepCopy {
    17    String filePath = "D:\BigData\JavaSE\yinzhengjieData\c.dat";
    18 
    19     /**
    20      * 深度拷贝,将对象序列化到文件
    21      */
    22     @Test
    23     public void testDeeplyCopy() throws Exception {
    24         Customer c = new Customer();
    25         c.setName("尹正杰");
    26 
    27         Order o1 = new Order();
    28         o1.setOrderno("0001");
    29 
    30         Order o2 = new Order();
    31         o2.setOrderno("0002");
    32 
    33         Item i1 = new Item();
    34         i1.setItemname("iphone 8 Plus");
    35 
    36         //建立关系
    37         c.getOrders().add(o1);
    38         c.getOrders().add(o2);
    39 
    40         o1.getItems().add(i1);
    41 
    42         //深度拷贝,将对象序列化到文件
    43         FileOutputStream fos = new FileOutputStream(filePath) ;
    44         ObjectOutputStream oos = new ObjectOutputStream(fos) ;
    45         oos.writeObject(c);
    46         oos.close();
    47         fos.close();
    48         System.out.println();
    49     }
    50 
    51 
    52     /**
    53      * 定义反序列化的代码
    54      */
    55     @Test
    56     public void testDeserialize() throws Exception {
    57         FileInputStream fis = new FileInputStream(filePath);
    58         ObjectInputStream ois = new ObjectInputStream(fis);
    59         Customer obj = (Customer)ois.readObject();
    60         ois.close();
    61         fis.close();
    62         System.out.println(obj.getName());
    63     }
    64 }
    65 
    66 /*
    67 以上代码执行结果如下:
    68     尹正杰
    69  */
  • 相关阅读:
    在没有源代码的情况下调试JAR包..
    Flex游戏篇——游戏开发概述
    CSDN、sina博客在Zoundry中登记的API URL 收藏
    标准博客 API .BLOG APIS
    SAXParseException An invalid XML character 问题的解决
    分布式存储方法
    拨号720错误解决记.txt
    xxx
    硬盘分区后的逻辑结构
    paip sms to blog.txt
  • 原文地址:https://www.cnblogs.com/yinzhengjie/p/8988003.html
Copyright © 2011-2022 走看看