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

    为什么要用序列化

    对于一个存在于Java虚拟机中的对象来说,其内部的状态只保持在内存中。JVM停止之后,这些状态就丢失了。在很多情况下,对象的内部状态是需要被持久化下来的。最直接的做法是保存到文件系统或是数据库之中,但这涉及到自定义存储格式以及繁琐的数据转换。序列化提供JVM中对象与字节数组织间的转换,从而实现了对象的持久化。
    序列化分为两大部分:序列化和反序列化。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。

    什么情况下需要序列化 :

      a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;  

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

      c)当你想通过RMI传输对象的时候; 

     
    序列化的代码实现

    待序列化的Java类只需要实现Serializable接口即可。Serializable仅是一个标记接口,并不包含任何需要实现的具体方法。实现该接口只是为了声明该Java类的对象是可以被序列化的。

    Serializeable接口的序列化和反序列化的实现是通过ObjectOutputStream和ObjectInputStream来完成的。ObjectOutputStream的writeObject方法可以把一个Java对象写入到流中,ObjectInputStream的readObject方法可以从流中读取一个Java对象。Eg: 

    private static void serializePerson() throws FileNotFoundException,IOException {
        try {
            User user = new User("Alex", "Cheng");
            ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("user.bin"));
            output.writeObject(user);
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    private static Person deserializePerson() throws IOException, Exception {
        try {
            ObjectInputStream input = new ObjectInputStream(new FileInputStream("user.bin"));
            User user = (User) input.readObject();
            System.out.println(user);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

     如果想对序列化的过程进行更加细粒度的控制,就需要在类中添加writeObject和对应的 readObject方法。在添加自己的逻辑之前,推荐的做法是先调用Java的默认实现。

    private void writeObject(ObjectOutputStream output) throws IOException {
        output.defaultWriteObject();
        output.writeUTF("Hello World");
    }
    
    private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException {
        input.defaultReadObject();
        String value = input.readUTF();
        System.out.println(value);
    }

     

    什么样的数据能被序列化

    当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口

    - Java对象中的非静态和非瞬时域都会被包括进来,而与域的可见性声明没有关系。声明为static和transient类型的成员数据不能被序列化。这可能会导致某些不应该出现的域被包含在序列化之后 的字节数组中,比如密码等隐私信息。由于Java对象序列化之后的格式是固定的,其它人可以很容易的从中分析出其中的各种信息。对于这种情况,一种解决办法是把域声明为transient。另一种是使用serialPersistentFields声明,即只有firstName这个域是要被序列化的。

    private static final ObjectStreamField[] serialPersistentFields = {
      new ObjectStreamField("firstName", String.class)
    };

    在通过ObjectInputStream的readObject方法读取到一个对象之后,这个对象是一个新的实例,但是其构造方法是没有被调用的,其中的域的初始化代码也没有被执行。对于那些没有被序列化的域,在新创建出来的对象中的值都是默认的。这有可能会造成一些隐含的错误。调用者并不知道对象是通过一般的new操作符来创建的,还是通过反序列化所得到的。解决的办法就是在类的readObject方法里面,再执行所需的对象初始化逻辑。

    Serializable interface doesn't have any method. 

    当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

    序列化的原理

    通过在实现了Serializable接口的类中定义一个序列号private static final long serialVersionUID = xxxxL; 该序列号在反序列化过程中用于验证序列化对象的,它是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段。对于开发人员来说,需要记得的就是在版本更新过程中保持该值不变。

    如果用户没有自己声明一个serialVersionUID,接口会默认生成一个,但建议自己定义。因为默认的serialVersionUID对于class的细节非常敏感,如果在序列化之后修改了类的定义,那么反序列化得到的serialVersionUID将会和原来不同

    为什么要用RMI技术

    RMI(Remote Method Invocation)是Java中的远程过程调用(Remote Procedure Call,RPC)实现,是一种分布式Java应用的实现方式。它的目的在于对开发人员屏蔽横跨不同JVM和网络连接等细节,使得分布在不同JVM上的对象像是存在于一个统一的JVM中一样,可以很方便的互相通讯。

    RMI的序列化机制

    为了通过Java的序列化机制来进行传输,远程接口中的方法的参数和返回值,要么是Java的基本类型,要么是远程对象,要么是实现了 Serializable接口的Java类。当客户端通过RMI注册表找到一个远程接口的时候,所得到的其实是远程接口的一个动态代理对象。当客户端调用其中的方法的时候,方法的参数对象会在序列化之后,传输到服务器端。服务器端接收到之后,进行反序列化得到参数对象。并使用这些参数对象,在服务器端调用实际的方法。调用的返回值Java对象经过序列化之后,再发送回客户端。客户端再经过反序列化之后得到Java对象,返回给调用者。这中间的序列化过程对于使用者来说是透明的,由动态代理对象自动完成。除了序列化之外,RMI还使用了动态类加载技术。当需要进行反序列化的时候,如果该对象的类定义在当前JVM中没有找到,RMI会尝试从远端下载所需的类文件定义。可以在RMI程序启动的时候,通过JVM参数java.rmi.server.codebase来指定动态下载Java类文件的URL。

    JavaBean的序列化

    Bean的状态信息通常是在设计时配置的。这些状态信息必须保存起来,供程序启动的时候用。对象序列化就负责这个工作。

    Json的序列化

    • JSON.stringify() - 将对象序列化为JSON字符串
    • JSON.parse() - 将JSON数据解析为Javascript对象
  • 相关阅读:
    软件行业从事人员,计算机基础须知(三)---DOS命令相关
    软件行业从事人员,计算机基础须知(二)---系统介绍和进制转换说明
    软件行业从事人员,计算机基础须知(一)
    python操作数据库步骤以及操作过程中经常出现的异常
    selenium中验证码识别简单封装
    selenium对验证码识别校验解决方法
    retina屏幕截取验证码
    Nginx的负载均衡的那点事
    子网划分
    iptables 规则整理
  • 原文地址:https://www.cnblogs.com/qionglouyuyu/p/4615215.html
Copyright © 2011-2022 走看看