Java 定制的序列化和反序列化

Java 定制的序列化和反序列化

序列化是一种将对象的状态转换为字节流的机制。反序列化是一个相反的过程,字节流被用来在内存中重新创建实际的Java对象。这种机制被用来持久化对象。

为什么需要自定义序列化

在序列化过程中,如果我们使用’transient’关键字,可能会有数据丢失。Transient “关键字被用于我们不想序列化的变量。但有时,需要以不同于默认序列化的方式对其进行序列化(如在序列化之前进行加密等),在这种情况下,我们必须使用自定义的序列化和反序列化。

下面的程序说明了上述数据丢失的情况。

// Java program to illustrate loss of information
// because of transient keyword.
import java.io.*;
  
class GfgAccount implements Serializable {
  
    String username = "gfg_admin";
  
    transient String pwd = "geeks";
  
}
  
class CustomizedSerializationDemo {
    public static void main(String[] args) throws Exception
    {
        GfgAccount gfg_g1 = new GfgAccount();
  
        System.out.println("Username : " + gfg_g1.username + 
                                 "    Password : " + gfg_g1.pwd);
  
        FileOutputStream fos = new FileOutputStream("abc.ser");
  
        ObjectOutputStream oos = new ObjectOutputStream(fos);
  
        // writeObject() method present in GfgAccount class
        // will be automatically called by jvm
        oos.writeObject(gfg_g1);
  
        FileInputStream fis = new FileInputStream("abc.ser");
  
        ObjectInputStream ois = new ObjectInputStream(fis);
  
        // readObject() method present GfgAccount class
        // will be automatically called by jvm
        GfgAccount gfg_g2 = (GfgAccount)ois.readObject();
  
        System.out.println("Username : " + gfg_g2.username + 
                               "      Password : " + gfg_g2.pwd);
    }
}

输出:

Username : gfg_admin    Password : geeks
Username : gfg_admin    Password : null

Java中定制的序列化和反序列化
在上面的例子中,在序列化之前,账户对象可以提供适当的用户名和密码,但反序列化的账户对象只提供了用户名而没有密码。这是由于将密码变量声明为暂存变量。

因此,在默认的序列化过程中,由于 transient 关键字的存在,可能会出现信息丢失的情况。为了恢复这种损失,我们必须使用 自定义序列化

自定义序列化可以通过以下两种方法实现。

  1. private void writeObject(ObjectOutputStream oos) throws Exception : 这个方法将在序列化的时候由jvm自动执行(也称为回调方法)。因此,要在序列化过程中执行任何活动,必须只在这个方法中定义。

  2. private void readObject(ObjectInputStream ois) throws Exception : 这个方法将在反序列化时被jvm自动执行(也被称为Callback Methods)。因此,要在反序列化过程中执行任何活动,必须只在这个方法中定义。

注意: 在执行对象序列化时,我们必须在该类中定义上述两个方法。

// Java program to illustrate customized serialization
import java.io.*;
  
class GfgAccount implements Serializable {
  
    String username = "gfg_admin";
  
    transient String pwd = "geeks";
  
    // Performing customized serialization using the below two methods:
    // this method is executed by jvm when writeObject() on
    // Account object reference in main method is
    // executed by jvm.
    private void writeObject(ObjectOutputStream oos) throws Exception
    {
        // to perform default serialization of Account object.
        oos.defaultWriteObject();
  
        // epwd (encrypted password)
        String epwd = "123" + pwd;
  
        // writing encrypted password to the file
        oos.writeObject(epwd);
    }
  
    // this method is executed by jvm when readObject() on
    // Account object reference in main method is executed by jvm.
    private void readObject(ObjectInputStream ois) throws Exception
    {
        // performing default deserialization of Account object
        ois.defaultReadObject();
  
        // deserializing the encrypted password from the file
        String epwd = (String)ois.readObject();
  
        // decrypting it and saving it to the original password
        // string starting from 3rd  index till the last index
        pwd = epwd.substring(3);
    }
}
  
class CustomizedSerializationDemo {
    public static void main(String[] args) throws Exception
    {
        GfgAccount gfg_g1 = new GfgAccount();
  
        System.out.println("Username :" + gfg_g1.username +
                           "       Password :" + gfg_g1.pwd);
  
        FileOutputStream fos = new FileOutputStream("abc.ser");
  
        ObjectOutputStream oos = new ObjectOutputStream(fos);
  
        // writeObject() method on Account class will
        // be automatically called by jvm
        oos.writeObject(gfg_g1);
  
        FileInputStream fis = new FileInputStream("abc.ser");
  
        ObjectInputStream ois = new ObjectInputStream(fis);
  
        GfgAccount gfg_g2 = (GfgAccount)ois.readObject();
  
        System.out.println("Username :" + gfg_g2.username + 
                             "       Password :" + gfg_g2.pwd);
    }
}

输出:

Username :gfg_admin    Password :geeks
Username :gfg_admin    Password :geeks

Java中定制的序列化和反序列化

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程