zoukankan      html  css  js  c++  java
  • java对象序列化

    java对象序列化

    1 概述

    1.1 概念
    对象序列化机制(Object Serialzation)是Java语言内建的一种轻量级持久化方式,可以容易的在JVM的活动对象信息字节序列之间转化(序列化与反序列化),用来屏蔽底层实现细节。

    1.2 意义

    1. 对于对象来说,其内部状态信息保存在内存中。当JVM停止运行后,状态信息就消失了。所以我们需要把对象的状态信息保存起来,这就是持久化
    2. 持久化一般来说都是把对象状态信息存放到数据库中。关系型数据库使用对象关系映射(ORM)的方法存放对象状态,例如Hibernate。也就直接把对象状态信息存放到数据库中,如Key-Value型数据库。
    3. Java对象序列化简单的保存对象状态信息,一般用于短期保存和RMI(远程方法调用)。

    2 实现

    2.1 基本对象序列化

    1. Java实现对象序列化只要实现Serializable接口即可。实现该接口表示该对象可以被序列化,实际的序列化由ObjectInputStream、ObjectOutputStream实现。
    2. ObjectOutputStream的writeObject()方法把对象写入字节序列中,ObejctInputStream的ReadObject()方法从字节序列中读出对象。
    3. 在读取与写入过程的时候,参数或者返回值是单个对象,但实际上操控的是对象图,其包括字段以及其依赖的对象。Java会自动帮你遍历对象图并逐个序列化。
    4. 对于Serializable对象,其是以二进制位为基础构造的,而不是以构造器进行构造的。
    5. View Code

    2.2 静态变量序列化以及继承、依赖序列化

    1. 静态变量没有被序列化。因为静态变量属于类的状态信息,而序列化是保存对象的状态信息。
    2. 前面说过Java对象序列化会把该对象的所有信息全部序列化,包括其所依赖的对象、父类对象等等。
    3. 如果该对象所依赖对象没有实现Serializable接口,则会抛出java.io.NotSerializableException。
    4. 如果该对象的父类对象没有实现Serializable接口,JVM就不会序列化父类对象。而一个Java对象构造必须先构造父类对象,才有子类对象,反序列化也不例外。所以反序列化时,为了构造父对象,只能调用父类的无参构造函数作为默认的父对象。因此当我们取父对象的字段时,它的值是调用父类无参构造函数后的值,如果没有无参构造函数则会抛出异常。
    5.  1 public class StudySerializable{
       2     public static void main(String[] args) 
       3             throws IOException, ClassNotFoundException{
       4         Car car = new Car();
       5 
       6         System.out.println("serialize");
       7         System.out.println(Car.staticNum);
       8         ObjectOutputStream out = new ObjectOutputStream(
       9                 new FileOutputStream("E://java//car.dat"));
      10         out.writeObject(car);
      11 
      12         Car.staticNum = 5;
      13 
      14         System.out.println("deserialize");
      15         ObjectInputStream in = new ObjectInputStream(
      16                 new FileInputStream("E://java//car.dat"));
      17         Car car1 = (Car) in.readObject();
      18         System.out.println(Car.staticNum);
      19     }
      20 }
      21 class Car implements Serializable{
      22     private static final long serialVersionUID = 8217070173670578351L;
      23     public static int staticNum  = 10;
      24 }output:
      25 serialize
      26 10
      27 deserialize
      28 5
      View Code

    2.3 transient关键字与序列化ID

    1. 当我们对对象进行初始化时,其会保留该对象所有的状态信息,即使这些信息是privates属性。我们可以使用transient关键字关闭其序列化,反序列化后该字段就为null或者为0。
    2. serialVersionUID是Java对象序列化ID。由于JVM的运行环境可能不一样,当我们反序列时,类名与序列化ID必须都相同才能反序列化成功。
    3.  1 public class StudySerializable{
       2     public static void main(String[] args) 
       3             throws IOException, ClassNotFoundException{
       4         User user = new User("kanyuxia@outlook.com ", "123456");
       5 
       6         System.out.println("serialize");
       7         System.out.println(user);
       8         ObjectOutputStream out = new ObjectOutputStream(
       9                 new FileOutputStream("E:\java\user.dat"));
      10         out.writeObject(user);
      11 
      12         System.out.println("deserialize");
      13         ObjectInputStream in = new ObjectInputStream(
      14                 new FileInputStream("E:\java\user.dat"));
      15         User user1 = (User) in.readObject();
      16         System.out.println(user1);
      17     }
      18 }
      19 class User implements Serializable {
      20     private static final long serialVersionUID = 4936874859415237692L;
      21     private String userName;
      22     private transient String password;
      23 
      24     User(String userName, String password){
      25         this.userName = userName;
      26         this.password = password;
      27     }
      28 
      29     @Override
      30     public String toString() {
      31         return "userName: " + userName + " password: " + password;
      32     }
      33 }
      View Code

    2.4 自定义序列化

    1. JVM在序列化、反序列化对象时,会首先检查该对象是否有readObject()、writeObject()方法(利用反射机制搜索)。如果有,则会使用它。
    2. 在添加自己的逻辑之前,推荐的做法是先调用Java的默认实现。在writeObject方法中通过ObjectOutputStream的defaultWriteObject来完成,在readObject方法则通过ObjectInputStream的defaultReadObject来实现。
    3.  1 public class StudySerializable{
       2     public static void main(String[] args)
       3             throws IOException, ClassNotFoundException{
       4         User user = new User("kanyuxia@outlook.com ", "123456");
       5 
       6         System.out.println("serialize");
       7         System.out.println(user);
       8         ObjectOutputStream out = new ObjectOutputStream(
       9                 new FileOutputStream("E:\java\user.dat"));
      10         out.writeObject(user);
      11 
      12         System.out.println("deserialize");
      13         ObjectInputStream in = new ObjectInputStream(
      14                 new FileInputStream("E:\java\user.dat"));
      15         User user1 = (User) in.readObject();
      16         System.out.println(user1);
      17     }
      18 }
      19 class User implements Serializable {
      20     private static final long serialVersionUID = 4936874859415237692L;
      21     private String userName;
      22     private transient String password;
      23 
      24     private void writeObject(ObjectOutputStream outputStream)
      25             throws IOException, ClassNotFoundException {
      26         outputStream.defaultWriteObject();
      27         outputStream.writeObject(password);
      28     }
      29 
      30     private void readObject(ObjectInputStream inputStream)
      31             throws IOException, ClassNotFoundException {
      32         inputStream.defaultReadObject();
      33         password = (String) inputStream.readObject();
      34     }
      35 
      36     User(String userName, String password){
      37         this.userName = userName;
      38         this.password = password;
      39     }
      40 
      41     @Override
      42     public String toString() {
      43         return "userName: " + userName + " password: " + password;
      44     }
      45 }output:
      46 serialize
      47 userName: kanyuxia@outlook.com  password: 123456
      48 deserialize
      49 userName: kanyuxia@outlook.com  password: 123456
      View Code

    2.5 序列化安全性以及RMI

    1. Java对象序列化之后的内容格式是公开的。所以可以很容易的从中提取出各种信息。所以我们可以通过自定义序列化进行该对象一些字段的加密、解密。
    2. RMI(Remote Method Invocation)是Java中的远程过程调用(Remote Procedure Call,RPC)实现,是一种分布式Java应用的实现方式。
    3. 上诉方式我都没有实现,先写在这里,以后用到了再来写。

    2.6 序列化与反序列化

    1. 序列化与反序列化是我们经常遇到的,上面说的序列化与反序列化都是Java自带的序列化机制,其不算高效、通用。我们在使用Key-Value型数据库时,例如Redis时可能需要其它一些高效的序列化框架。
    2. 自己在慕课网上学习Seckill时,老师讲到过一点,当时都不懂什么意思,仅仅跟着用了,现在理解了许多。
    3. 这里有篇美团技术文章,可以去看看相关的知识。

    3 Reference

    http://www.infoq.com/cn/articles/cf-java-object-serialization-rmi
    https://www.ibm.com/developerworks/cn/java/j-lo-serial/

  • 相关阅读:
    java 项目的CAS搭建
    OpenStack Grizzly版本(Ubuntu 12.04)配置
    存储介质管理
    软件包管理
    终端和键盘
    Shell环境(environment)和配置(configuration)
    Linux 基本命令入门
    iptables的原理及使用
    移动小球 (sicily 1934) (双向链表)
    1010 Tempter of the Bone (杭电) (图Graph)
  • 原文地址:https://www.cnblogs.com/maying3010/p/6510798.html
Copyright © 2011-2022 走看看