美文网首页
Serializable 序列化

Serializable 序列化

作者: gczxbb | 来源:发表于2019-05-22 23:15 被阅读0次

    序列化,即把一个对象内容,转换成字节序列。反序列化,将字节序列恢复成一个对象的过程。若一个对象需要序列化,实现 Serializable 接口。一个例子。

    public class SerializableMain {
        public static void main(String[] args) {
            User user=new User("name_one","age_one","height_one");
            try {
                File file=new File("C:\\Users\\name\\Desktop\\DemoFile");
                if(!file.exists()) {
                    file.createNewFile();
                }
                //序列化
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(file));
                oos.writeObject(user);
                oos.close();
                //反序列化
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
                User userTemp=(User)ois.readObject();
                System.out.println(userTemp.toString());
            }catch(Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    User对象,实现Serializable接口才可以将该对象序列化和反序列化。将对象序列化输出到文件流时,如果未实现Serializable接口,将抛出异常。

    java.io.NotSerializableException: User
        at java.io.ObjectOutputStream.writeObject0(Unknown Source)
        at java.io.ObjectOutputStream.writeObject(Unknown Source)
        at SerializableMain.main(SerializableMain.java:19)
    

    从文件中反序列化一个对象时,(先实现接口完成序列化写入,再去掉接口),如果未实现Serializable接口,将抛出异常。

    java.io.InvalidClassException: User; class invalid for deserialization
        at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(Unknown Source)
        at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
        at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
        at java.io.ObjectInputStream.readObject0(Unknown Source)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at SerializableMain.main(SerializableMain.java:24)
    

    transient修饰的属性,不会被序列化和反序列化。序列化时,忽略该属性写入字节数组,反序列化时,不会读取属性。在User类的age属性加上该修饰。反序列化时,打印结果将是null。

    User [name=name_one, age=null, height=height_one]
    

    静态字段不会被序列化。在User类加上一个静态字段address=shanghai,先进行一次User对象序列化输出,然后,将该字段改为beijing,注释掉序列化部分,只进行反序列化。这时,反序列化address值并不是shanghai,而是beijing。说明第一次序列化时,并没有将静态字段写入。
    serialVersionUID的作用。不加该项时,序列化,将会采用Java自动生成的值,正常情况下,序列化和反序列化是没问题的。如果在User类新增一个字段weight,注释掉序列化的代码,直接进行反序列化,将抛出异常。

    java.io.InvalidClassException: User; local class incompatible: 
            stream classdesc serialVersionUID = 4765874944071207273, 
            local class serialVersionUID = -4975271451414878760
        at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
        at java.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
        at java.io.ObjectInputStream.readClassDesc(Unknown Source)
        at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
        at java.io.ObjectInputStream.readObject0(Unknown Source)
        at java.io.ObjectInputStream.readObject(Unknown Source)
        at SerializableMain.main(SerializableMain.java:21)
    

    反序列化serialVersionUID和当前User对象的serialVersionUID不同,因为我该值是Java自动生成的,根据该类属性计算生成,保存文件的内容是没有weight属性的,因此,生成的serialVersionUID不同。User类中加上serialVersionUID字段。对字段属性的修改再反序列化将不会报错。

    private static final long serialVersionUID = 1L;
    

    这次不改属性,当serialVersionUID=1L序列化完成后,注释掉序列化代码,改serialVersionUID=2344,进行反序列化,同样将报serialVersionUID不相等的异常,

    java.io.InvalidClassException: User; local class incompatible: 
            stream classdesc serialVersionUID = 1, 
            local class serialVersionUID = 2344
        at java.io.ObjectStreamClass.initNonProxy(Unknown Source)
    

    因此,serialVersionUID值一定要自己写上,且不要随便改变,不要让Java自动生成。否则,在更新对象属性(Java自动生成会改变),再去进行反序列化时,将无法识别出老数据。


    任重而道远

    相关文章

      网友评论

          本文标题:Serializable 序列化

          本文链接:https://www.haomeiwen.com/subject/zjwpzqtx.html