java反序列化exp Java反序列化工具_java反序列化工具


序列化不仅在java面试中是个较为常见的面试题,而且在实际项目开发中也是经常打交道的,今天咱们就来聊一聊关于序列化与反序列化那些事儿。

什么是序列化和反序列化?

序列化:把对象转换为字节序列的过程。

反序列化:把字节序列恢复为对象的过程。

序列化的作用

(1) 把对象的字节序列永久地保存到硬盘上(通常存放在一个文件中);

(2) 在网络上传送对象的字节序列。

java代码实现序列化

(1)使用序列化与不使用的区别

现在准备把一个对象中的数据写入到硬盘,并读取之前往硬盘写入的数据。

建立一个猫的实体类


/**
 * @Description: 猫的实体类
 * @CreateDate: 2019/6/24 10:42
 */
public class Cat {
    private String name;
    private Integer age;
    private String color;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Cat{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", color='" + color + ''' +
                '}';
    }
}


测试类


import java.io.*;

/**
 *  序列化测试
 */
public class DemoSerializable04 {
    public static void main(String args[]) throws IOException, ClassNotFoundException {
        serialization();
        deserialization();
        }



    //序列化
    public  static void serialization() throws IOException {
        Cat cat = new Cat();
        cat.setName("Tom");
        cat.setAge(3);
        cat.setColor("black");
        //指定位置到输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File("D:temporary/cat.txt")));
        //把对象序列化到输出流中
        oos.writeObject(cat);
        System.out.println("对象序列化成功!");
        //关闭Io流
        oos.close();
    }


    //反序列化
    public static void deserialization() throws IOException, ClassNotFoundException {
        //指定位置到输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("D:temporary/cat.txt")));
        //读取输入流中的对象
        Cat cat = (Cat) ois.readObject();
        System.out.println("对象反序列化成功!");
        System.out.println(cat.toString());
    }

}


执行后,会发现抛异常,提示无法往硬盘写入数据。


D:bprogramSoftwarejdkjdk1.8.0_131binjava ...
Exception in thread "main" java.io.NotSerializableException: Cat
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at DemoSerializable04.serialization(DemoSerializable04.java:23)
	at DemoSerializable04.main(DemoSerializable04.java:8)


这时候在对Cat对象实现Serializable,再次运行,OK,可以正常写并读数据。


D:bprogramSoftwarejdkjdk1.8.0_131binjava "...
对象序列化成功!
对象反序列化成功!
Cat{name='Tom', age=3, color='black'}


(2)serialVersionUID有何作用

现在Cat类中添加一个type的属性,并只执行反序列化,这时候程序就会抛出异常,标明实体中的uid与反序列化时生成的uid不同。


D:bprogramSoftwarejdkjdk1.8.0_131binjava "...
Exception in thread "main" java.io.InvalidClassException: Cat; local class incompatible: stream classdesc serialVersionUID = -1858351317844297891, local class serialVersionUID = 4327445649782673671
	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1843)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1713)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2000)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1535)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
	at DemoSerializable04.deserialization(DemoSerializable04.java:35)
	at DemoSerializable04.main(DemoSerializable04.java:9)


解决uid不同的问题的答案,就是给实体类中给serialVersionUID 赋值(private static final long serialVersionUID = 1L),这样就可以

保证uid不会有冲突了。

(3)static 与transient关键字对序列化的影响

现在往Cat实体类中的age属性前加上static进行修饰,接着运行测试类。卧槽,这和书上说的不一样啊,static修饰的属性不能被序列

化啊,但其实static的静态成员变量是不能被序列化这个观点是正确的,造成可以拿到static序列化之后的假象是因为static 属于类的,得到

的是JVM已经加载好的Class的static变量的值。


D:bprogramSoftwarejdkjdk1.8.0_131binjava ...
对象序列化成功!
对象反序列化成功!
Cat{name='Tom', age=6, color='black', type='null'}


单独执行读取代码后,会发现age值为null,可以证明static的静态成员变量并不能被序列化。


D:bprogramSoftwarejdkjdk1.8.0_131binjava ...
对象反序列化成功
Cat{name='Tom', age=null, color='black', type='null'}


同理,在Cat类中color属性前添加transient进行修饰,然后单独执行读取代码后,会发现color值为null,transient修饰的属性不能被序列化。


D:bprogramSoftwarejdkjdk1.8.0_131binjava ...
对象反序列化成功!
Cat{name='Tom', age=null, color='null', type='null'}


序列化的方式(性能由低至高)

Java Serialization(主要是采用JDK自带的Java序列化实现,性能很不理想)

Json(目前有两种实现,一种是采用的阿里的fastjson库,另一种是采用dubbo中自己实现的简单json库)

FastJson(阿里的fastjson库)

Hession(它基于HTTP协议传输,使用Hessian二进制序列化,对于数据包比较大的情况比较友好。)

Dubbo Serialization(阿里dubbo序列化)

FST(高性能、序列化速度大概是JDK的4-10倍,大小是JDK大小的1/3左右)

Kryo

总结

序列化主要是为了跨平台,实现对象的一致性,可在不同的平台上,保持自己原有的属性和方法不变。