序列化与反序列化

/ Java SE / 0 条评论 / 3351浏览

简介

对象序列化指将保存在内存的对象数据转换为二进制数据流进行传输的操作。比如传输到网络或文件或保存至数据库等等,在Spring、Mybatis、JSON等框架或工具包中使用的非常多。接下来简单地学习一下Java中的序列化。

Java为什么需要序列化?

对象序列化就是为了数据传输,在你的代码里是对象格式,而传输的时候不可能还保持这个对象的样子。当两个进程在进行远程通信时,彼此可以发送各种类型的数据,无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送,接收方需要将二进制流转换为对象形式,此过程称之为反序列化。

不是所有的类都是可以序列化的,它必须实现java.io.Serializable接口,这个接口是属于声明式接口,其中没有任何方法,就表示一种能力说明。

Java中的两个声明式接口:Cloneable、Serializable

序列化与反序列化

要进行序列化需要有两个类的支持:

序列化

为了方便演示,这里将一个类序列化到一个文件中去。先看一下ObjectOutputStream类的基本信息: 继承结构:

java.lang.Object
    java.io.OutputStream
        java.io.ObjectOutputStream

类定义:

public class ObjectOutputStream
extends OutputStream
implements ObjectOutput, ObjectStreamConstants

构造方法:

public ObjectOutputStream(OutputStream out) throws IOException

主要方法:

写入一个对象:public final void writeObject(Object obj) throws IOException
写入一个字节:public void write(int val) throws IOException
写入一个Xxx类型的数据(int、float、double、char、boolean、long):public void writeXxx(Xxx val) throws IOException

接下来用一个示例来简单应用一下序列化:

package language;

import java.io.*;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 21:16 2019/1/28
 * @Description:
 */
public class SerialTest {
    public static void main(String[] args) throws Exception{
        File file = new File("D:"+File.separator+"book.ser");   //  将类的二进制数据保存到此文件
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file)); //  示例一个序列化对象,并传入文件的输出流
        objectOutputStream.writeObject(new Book("java",99.99)); //  将静态内部内实例化并对其序列化写入文件
        objectOutputStream.close(); //  关闭流
    }
    static class Book implements Serializable{

        private String title;
        private double price;

        public Book(String title,double price){
            this.title=title;
            this.price=price;
        }

        @Override
        public String toString() {
            return "title="+title+",price="+price;
        }
    }
}

最后我们的book.ser文件内已经成功写入了Book类对象的二进制数据,用sublime打开该文件的内容如下:

aced 0005 7372 0018 6c61 6e67 7561 6765
2e53 6572 6961 6c54 6573 7424 426f 6f6b
f9ae 1c35 5b5e 0b6d 0200 0244 0005 7072
6963 654c 0005 7469 746c 6574 0012 4c6a
6176 612f 6c61 6e67 2f53 7472 696e 673b
7870 4058 ff5c 28f5 c28f 7400 046a 6176
61

反序列化

反序列化就是将二进制流转换为类对象,这里仍然将上面创建好的类进行反序列化输出,看看能否输出Book类对象,先看看ObjectInputStream类的基本信息:

继承结构:

java.lang.Object
    java.io.InputStream
        java.io.ObjectInputStream

类定义:

public class ObjectInputStream
extends InputStream
implements ObjectInput, ObjectStreamConstants

构造方法:

public ObjectInputStream(InputStream in) throws IOException

主要方法:

读取对象:public final Object readObject() throws IOException, ClassNotFoundException
读取一个字节:public char read() throws IOException
读取Xxx类型数据(int、float、double、short、boolean、char):public Xxx readXxx() throws IOException

代码示例:

package language;

import java.io.*;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 21:16 2019/1/28
 * @Description:
 */
public class SerialTest {
    public static void main(String[] args) throws Exception{
        File file = new File("D:"+File.separator+"book.ser");   //  将类的二进制数据保存到此文件
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file)); //  示例反序列化类并传入文件的输入流
        Object object = objectInputStream.readObject();     //  先读取成Object对象
        Book book = (Book) object;      //  向下转型
        System.out.println(book);
    }
    static class Book implements Serializable{

        private String title;
        private double price;

        public Book(String title,double price){
            this.title=title;
            this.price=price;
        }

        @Override
        public String toString() {
            return "title="+title+",price="+price;
        }
    }
}

输出结果:

title=java,price=99.99

这正是上面序列化的对象,说明我们成功的将二进制数据反序列化成了对象。

transient关键字

有些时候如果不想将类的某个属性进行序列化,也就是说在以二进制传输的时候不对其值进行保存,可以使用transient关键字来修饰该属性即可,下面是测试代码,我现在讲price这个属性进行transient修饰。

先进行序列化:

package language;

import java.io.*;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 21:16 2019/1/28
 * @Description:
 */
public class SerialTest {
    public static void main(String[] args) throws Exception{
        File file = new File("D:"+File.separator+"book.ser");   //  将类的二进制数据保存到此文件
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file)); //  示例一个序列化对象,并传入文件的输出流
        objectOutputStream.writeObject(new Book("java",99.99)); //  将静态内部内实例化并对其序列化写入文件
        objectOutputStream.close(); //  关闭流
    }
    static class Book implements Serializable{

        private String title;
        private transient double price;

        public Book(String title,double price){
            this.title=title;
            this.price=price;
        }

        @Override
        public String toString() {
            return "title="+title+",price="+price;
        }
    }
}

在进行反序列化:

package language;

import java.io.*;

/**
 * @Author beifengtz
 * @Site www.beifengtz.com
 * @Date Created in 21:16 2019/1/28
 * @Description:
 */
public class SerialTest {
    public static void main(String[] args) throws Exception{
        File file = new File("D:"+File.separator+"book.ser");   //  将类的二进制数据保存到此文件
        ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file)); //  示例反序列化类并传入文件的输入流
        Object object = objectInputStream.readObject();     //  先读取成Object对象
        Book book = (Book) object;      //  向下转型
        System.out.println(book);
    }
    static class Book implements Serializable{

        private String title;
        private transient double price;

        public Book(String title,double price){
            this.title=title;
            this.price=price;
        }

        @Override
        public String toString() {
            return "title="+title+",price="+price;
        }
    }
}

现在的输出结果:

title=java,price=0.0

price的值为默认值,说明此时二进制文件book.ser里面并未保存price的值,这就是transient关键字的作用。序列化与反序列化是非常重要的一个概念,在JSON格式转换、网络数据处理、数据持久化处理以及Redis、ElasticSearch等NoSQL做存储时都会用到序列化与反序列化,虽然平时在使用的时候没什么感觉,但是框架内部其实都是已经为我们封装好了的,如果不使用框架,那么序列化必定是经常用到的。

微信公众号浏览体验更佳,在这里还有更多优秀文章为你奉上,快来关注吧!

北风IT之路