zoukankan      html  css  js  c++  java
  • Java学习笔记(十七)——java序列化

    【前面的话】

          做项目总是要用到很多东西,遇到一个新的知识,并不是这个知识出来的时间短,而是对于自己来说是新的,所以就需要自己去学习,希望今后可以提高学习的效率。

          这篇文章是关于Java 序列化的,选择性阅读。

    【知识点】

    一、什么叫序列化?

          我们都知道对象是暂时保存在内存中的,不能用U盘考走了,有时为了使用介质转移对象,并且把对象的状态保持下来,就需要把对象保存下来,这个过程就叫做序列化,通俗点,就是把人的魂(对象)收伏成一个石子(可传输的介质)。

    二、什么叫反序列化?

          就是再把介质中的东西还原成对象,把石子还原成人的过程。

    三、可能的使用情况

          1. 当你想把的内存中的对象写入到硬盘的时候;

          比如说你的内存不够用了,那计算机就要将内存里面的一部分对象暂时的保存到硬盘中,等到要用的时候再读入到内存中,硬盘的那部分存储空间就是所谓的虚拟内存。在比如过你要将某个特定的对象保存到文件中,我隔几天在把它拿出来用,那么这时候就要实现Serializable接口;

          2. 当你想用套接字在网络上传送对象的时候;

          在进行java的Socket编程的时候,你有时候可能要传输某一类的对象,那么也就要实现Serializable接口;最常见的你传输一个字符串,它是JDK里面的类,也实现了Serializable接口,所以可以在网络上传输。

          3. 当你想通过RMI传输对象的时候;

          如果要通过远程的方法调用(RMI)去调用一个远程对象的方法,如在计算机A中调用另一台计算机B的对象的方法,那么你需要通过JNDI服务获取计算机B目标对象的引用,将对象从B传送到A,就需要实现序列化接口。

    四、Serializable接口

    1. Serializable接口:一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才是可序列化的。因此如果要序列化某些类的对象,这些类就必须实现Serializable接口。
    2. Serializable实现代码:
    1 public interface Serializable {
    2 }

          可以看出Serializable接口是一个空的接口,目的只有一个就是表示一个类的对象可以被序列化。这个标签是类可以被序列化的特性,表示这个类可以被序列化。

    五、Externalizable接口

    1. Externalizable接口:他是Serializable接口的子类
    2. Externalizable实现代码:
    1 public interface Externalizable extends java.io.Serializable {
    2     void writeExternal(ObjectOutput out) throws IOException;
    3     void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
    4 }

    六、Serializable接口和Externalizable接口区别

    1. Serializable一个对象想要被序列化,那么它的类就要实现此接口,这个对象的所有属性(包括private属性、包括其引用的对象)都可以被序列化和反序列化来保存、传递。
    2. Externalizable他是Serializable接口的子类,有时我们不希望序列化那么多,可以使用这个接口,这个接口的writeExternal()和readExternal()方法可以指定序列化哪些属性;

    【学习demo And 解释】

    一、Java实现序列化

          1. java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。

          2. java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。

          3. 对象序列化包括如下步骤:

             1)创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;

             2)通过对象输出流的writeObject()方法写对象。

          4. 对象反序列化的步骤如下:

             1)创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;

             2)通过对象输入流的readObject()方法读取对象。

          5. 代码实现:

           SerializableTest.java

     1 import java.io.*;
     2 import java.util.Date;
     3 
     4 public class SerializableTest {
     5     
     6     public static void main(String[] args) throws Exception {
     7         ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("objectFile.obj"));
     8         //序列化对象
     9         Customer customer = new Customer("阿蜜果", 24);
    10         out.writeObject("你好!");
    11         out.writeObject(new Date());
    12         out.writeObject(customer);//写入实现了序列化的对象
    13         out.writeInt(123); //写入基本类型数据
    14         out.close();
    15         //反序列化对象
    16         ObjectInputStream in = new ObjectInputStream(new FileInputStream("objectFile.obj"));
    17         System.out.println("obj1=" + (String) in.readObject());
    18         System.out.println("obj2=" + (Date) in.readObject());
    19         Customer obj3 = (Customer) in.readObject();
    20         System.out.println("obj3=" + obj3);
    21         int obj4 = in.readInt();
    22         System.out.println("obj4=" + obj4);
    23         in.close();
    24         }
    25     }
    26 class Customer implements Serializable {
    27     private String name;
    28     private int age;
    29     public Customer(String name, int age) {
    30         this.name = name;
    31         this.age = age;
    32         }
    33     public String toString() {
    34         return "name=" + name + ", age=" + age;
    35         }
    36     }

          6. 运行结果:

    1 obj1=你好!
    2 obj2=Thu Apr 03 09:12:09 CST 2014
    3 obj3=name=阿蜜果, age=24
    4 obj4=123

    二、Java实现序列化的时候使用关键字

          1. transient是Java语言的关键字,用来表示一个域不是该对象序列化的一部分。当一个对象被序列化的时候,transient型变量的值不包括在序列化的表示中,然而非transient型的变量是被包括进去的。  

          2. demo代码

         其中Password定义为transient型,在输出的时候,就会不被序列化。输出null。

         SerializableTest.java

      1 import java.io.*; 
      2 
      3 public class SerializableTest { 
      4     public static void main(String args[]) { 
      5         testObjectSeri(); 
      6         testObjectInSeri(); 
      7     } 
      8     /** 
      9      * 对象序列化测试 
     10      */ 
     11     public static void testObjectSeri() { 
     12         Person person = new Person("熔岩", "341022225562156", "lavasoft"); 
     13         FileOutputStream fos = null; 
     14         ObjectOutputStream oos = null; 
     15         try { 
     16             fos = new FileOutputStream("person.dat"); 
     17             oos = new ObjectOutputStream(fos); 
     18             oos.writeObject(person); 
     19         } catch (FileNotFoundException e) { 
     20             System.out.println("找不到指定的文件!"); 
     21             e.printStackTrace(); 
     22         } catch (IOException e) { 
     23             e.printStackTrace(); 
     24         } finally { 
     25             try { 
     26                 oos.flush(); 
     27                 oos.close(); 
     28             } catch (IOException e) { 
     29                 e.printStackTrace(); 
     30             } 
     31         } 
     32     } 
     33     /** 
     34      * 对象反序列化测试 
     35      */ 
     36     public static void testObjectInSeri() { 
     37         FileInputStream fis = null; 
     38         ObjectInputStream ois = null; 
     39         Person person = null; 
     40         try { 
     41             fis = new FileInputStream("person.dat"); 
     42             ois = new ObjectInputStream(fis); 
     43             person = (Person) ois.readObject(); 
     44         } catch (FileNotFoundException e) { 
     45             e.printStackTrace(); 
     46         } catch (IOException e) { 
     47             e.printStackTrace(); 
     48         } catch (ClassNotFoundException e) { 
     49             e.printStackTrace(); 
     50         } finally { 
     51             try { 
     52                 ois.close(); 
     53             } catch (IOException e) { 
     54                 e.printStackTrace(); 
     55             } 
     56         } 
     57         System.out.println(person.toString()); 
     58     } 
     59 } 
     60 /** 
     61 * 测试序列化所用的类 
     62 */ 
     63 class Person implements Serializable { 
     64     private String username; 
     65     private String cardNumber; 
     66     private transient String password; 
     67     public Person(String username, String cardNumber, String password) { 
     68         this.username = username; 
     69         this.cardNumber = cardNumber; 
     70         this.password = password; 
     71     } 
     72     public String getUsername() { 
     73         return username; 
     74     } 
     75     public void setUsername(String username) { 
     76         this.username = username; 
     77     } 
     78     public String getCardNumber() { 
     79         return cardNumber; 
     80     } 
     81     public void setCardNumber(String cardNumber) { 
     82         this.cardNumber = cardNumber; 
     83     } 
     84     public String getPassword() { 
     85         return password; 
     86     } 
     87     public void setPassword(String password) { 
     88         this.password = password; 
     89     } 
     90     public String toString() { 
     91         StringBuffer sb = new StringBuffer(this.getClass().getName()); 
     92         sb.append("["); 
     93         sb.append("
    	"); 
     94         sb.append("username=" + this.username); 
     95         sb.append("
    	"); 
     96         sb.append("cardNumber=" + this.cardNumber); 
     97         sb.append("
    	"); 
     98         sb.append("password=" + this.password); 
     99         sb.append("]"); 
    100         return sb.toString(); 
    101     } 
    102 }

      4. 运行结果:

    1 Person[
    2     username=熔岩
    3     cardNumber=341022225562156
    4     password=null]

    【几个问题】

    一、序列化版本serialVersionUID

          1. serialVersionUID作用: 

            序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性。 

            类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。显式地定义serialVersionUID有两种用途:

           1)在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;

           2)在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

          2. 有两种生成方式: 

            一个是默认的1L,比如:private static final long serialVersionUID = 1L;

            一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如: 

            private static final long serialVersionUID = xxxxL; 

           当你一个类实现了Serializable接口,如果没有定义serialVersionUID,Eclipse会提供这个 ,提示功能告诉你去定义 。在Eclipse中点击类中warning的图标一下,Eclipse就会自动给定两种生成的方式。如果不想定义它,在Eclipse的设置中也 可以把它关掉的,设置如下: 

           Window ==> Preferences ==> Java ==> Compiler ==> Error/Warnings ==> Potential programming problems 

           将Serializable class without serialVersionUID的warning改成ignore即可。 

    二、其他说明:

    1. 基本类型的数据可以直接序列化
    2. 对象要被序列化,它的类必须要实现Serializable接口;如果一个类中有引用类型的实例变量,这个引用类型也要实现Serializable接口。

          如果不想让引用类实现Serializable接口,并且让本类成功序列化也可以,使用transient关键字。

    【参考资料】

    1. Serializable 作用
    2. Java对象的序列化和反序列化实践
    3. java.io 序列化 总结(一)---Serializable 和 Externalizable 的区别与联系

    【后面的话】

         随波逐流虽易,努力生活不易,且行且珍惜。

    ——TT

  • 相关阅读:
    什么是webview
    juqery.fn.extend和jquery.extend
    LeetCode
    5. Longest Palindromic Substring
    42. Trapping Rain Water
    11. Container With Most Water
    621. Task Scheduler
    49. Group Anagrams
    739. Daily Temperatures
    3. Longest Substring Without Repeating Characters
  • 原文地址:https://www.cnblogs.com/xt0810/p/3642904.html
Copyright © 2011-2022 走看看