zoukankan      html  css  js  c++  java
  • Serializable

    ObjectOutputStream(序列化)ObjectInputStream(反序列化)

    serialVersionUID

    字段不参与序列化

    Externalizable

    序列化的应用

    ObjectOutputStream(序列化)ObjectInputStream(反序列化)

    package com.datang.netty.serializabletest;
    
    import java.io.Serializable;
    
    public class Amimal{
        private String hobby;
        private String eat;
        private int age;
        public String getHobby() {
            return hobby;
        }
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
        public String getEat() {
            return eat;
        }
        public void setEat(String eat) {
            this.eat = eat;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Amimal [hobby=" + hobby + ", eat=" + eat + ", age=" + age + "]";
        }
        
        
    }
    View Code
    package com.datang.netty.serializabletest;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class Run {
        public static void main(String[] args)throws Exception {
            
            Amimal amimal = new Amimal();
            amimal.setAge(11);
            amimal.setEat("鸡蛋");
            amimal.setHobby("打游戏");
            
            
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\Users\bykj\Desktop\obj.txt"));
            oos.writeObject(amimal);
            
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\Users\bykj\Desktop\obj.txt"));
            Amimal a = (Amimal)ois.readObject();
            System.out.println(a);
        }
    }
    View Code

    ObjectOutputStream将对象写入到本地文件,ObjectInputStream从本地文件中获取一个对象。这一对方法是需要实现Serializable接口的。以上代码中Animal并未实现Serializable所以会抛出一个java.io.NotSerializableException: com.datang.netty.serializabletest.Amimal异常。

    Animal实现Aerializable后执行结果如下

    Amimal [hobby=打游戏, eat=鸡蛋, age=11]

    查看源码可以发现如果被写入本地的对象类型不是String,不是数组,不是Enum,也不是Serializable便会抛出异常。

     public final void writeObject(Object obj) throws IOException {
            if (enableOverride) {
                writeObjectOverride(obj);
                return;
            }
            try {
                writeObject0(obj, false);
            } catch (IOException ex) {
                if (depth == 0) {
                    writeFatalException(ex);
                }
                throw ex;
            }
        }
    View Code
     private void writeObject0(Object obj, boolean unshared)
            throws IOException
        {
            boolean oldMode = bout.setBlockDataMode(false);
            depth++;
            try {
                // handle previously written and non-replaceable objects
                int h;
                if ((obj = subs.lookup(obj)) == null) {
                    writeNull();
                    return;
                } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                    writeHandle(h);
                    return;
                } else if (obj instanceof Class) {
                    writeClass((Class) obj, unshared);
                    return;
                } else if (obj instanceof ObjectStreamClass) {
                    writeClassDesc((ObjectStreamClass) obj, unshared);
                    return;
                }
    
                // check for replacement object
                Object orig = obj;
                Class<?> cl = obj.getClass();
                ObjectStreamClass desc;
                for (;;) {
                    // REMIND: skip this check for strings/arrays?
                    Class<?> repCl;
                    desc = ObjectStreamClass.lookup(cl, true);
                    if (!desc.hasWriteReplaceMethod() ||
                        (obj = desc.invokeWriteReplace(obj)) == null ||
                        (repCl = obj.getClass()) == cl)
                    {
                        break;
                    }
                    cl = repCl;
                }
                if (enableReplace) {
                    Object rep = replaceObject(obj);
                    if (rep != obj && rep != null) {
                        cl = rep.getClass();
                        desc = ObjectStreamClass.lookup(cl, true);
                    }
                    obj = rep;
                }
    
                // if object replaced, run through original checks a second time
                if (obj != orig) {
                    subs.assign(orig, obj);
                    if (obj == null) {
                        writeNull();
                        return;
                    } else if (!unshared && (h = handles.lookup(obj)) != -1) {
                        writeHandle(h);
                        return;
                    } else if (obj instanceof Class) {
                        writeClass((Class) obj, unshared);
                        return;
                    } else if (obj instanceof ObjectStreamClass) {
                        writeClassDesc((ObjectStreamClass) obj, unshared);
                        return;
                    }
                }
    
                // remaining cases
                if (obj instanceof String) {
                    writeString((String) obj, unshared);
                } else if (cl.isArray()) {
                    writeArray(obj, desc, unshared);
                } else if (obj instanceof Enum) {
                    writeEnum((Enum<?>) obj, desc, unshared);
                } else if (obj instanceof Serializable) {
                    writeOrdinaryObject(obj, desc, unshared);
                } else {
                    if (extendedDebugInfo) {
                        throw new NotSerializableException(
                            cl.getName() + "
    " + debugInfoStack.toString());
                    } else {
                        throw new NotSerializableException(cl.getName());
                    }
                }
            } finally {
                depth--;
                bout.setBlockDataMode(oldMode);
            }
        }
    View Code

    serialVersionUID

    在Eclipse编辑器或IDEA编辑器时实现Serializable接口编辑器会提示我们做额外的操作。

    先看下有几种处理方案。

    1 private static final long serialVersionUID = 1L;

    2 private static final long serialVersionUID = 7643364732831133867L;

    3 @SuppressWarnings("serial")

    4 忽略它的提示,什么都不做。

    第四种方案忽略提示什么都不做。执行Run后执行Run2此时结果是正确的。

    package com.datang.netty.serializabletest;
    
    import java.io.Serializable;
    
    public class Amimal implements Serializable{
        private String hobby;
        private String eat;
        private int age;
        
        
        
        public String getHobby() {
            return hobby;
        }
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
        public String getEat() {
            return eat;
        }
        public void setEat(String eat) {
            this.eat = eat;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Amimal [hobby=" + hobby + ", eat=" + eat + ", age=" + age + "]";
        }
        
        
    }
    View Code
    package com.datang.netty.serializabletest;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class Run {
        public static void main(String[] args)throws Exception {
            
            Amimal amimal = new Amimal();
            amimal.setAge(11);
            amimal.setEat("鸡蛋");
            amimal.setHobby("打游戏");
            
            
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\Users\bykj\Desktop\obj.txt"));
            oos.writeObject(amimal);
            
    
        }
    }
    View Code
    package com.datang.netty.serializabletest;
    
    import java.io.FileInputStream;
    import java.io.FileOutputStream;
    import java.io.ObjectInputStream;
    import java.io.ObjectOutputStream;
    
    public class Run2 {
        public static void main(String[] args)throws Exception {
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\Users\bykj\Desktop\obj.txt"));
            Amimal a = (Amimal)ois.readObject();
            System.out.println(a);
        }
    }
    View Code

    若此时我们修改了Animal类再次执行Run2就会抛出异常。异常原因为Class中的serialVersionUID 和和本地文件中的serialVersionUID不相同导致的。得出结论,就算我们不使用1,2,3编译器也会自动帮我们生成serialVersionUID。

    package com.datang.netty.serializabletest;
    
    import java.io.Serializable;
    
    public class Amimal implements Serializable{
        private String hobby;
        private String eat;
        private int age;
        
        public void a() {}
        
        public String getHobby() {
            return hobby;
        }
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
        public String getEat() {
            return eat;
        }
        public void setEat(String eat) {
            this.eat = eat;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Amimal [hobby=" + hobby + ", eat=" + eat + ", age=" + age + "]";
        }
        
        
    }
    View Code
    Exception in thread "main" java.io.InvalidClassException: com.datang.netty.serializabletest.Amimal; local class incompatible: stream classdesc serialVersionUID = 7643364732831133867, local class serialVersionUID = 6225763375310236200

    第三种方案其实只是将警告给抑制了,只是让有强迫症的程序员看起来舒服点,并没有做其他操作。重复第四种方案的测试步骤得出相同的结果。

    package com.datang.netty.serializabletest;
    
    import java.io.Serializable;
    
    @SuppressWarnings("serial")
    public class Amimal implements Serializable{
        private String hobby;
        private String eat;
        private int age;
        
        public int a;
        
        
        public String getHobby() {
            return hobby;
        }
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
        public String getEat() {
            return eat;
        }
        public void setEat(String eat) {
            this.eat = eat;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Amimal [hobby=" + hobby + ", eat=" + eat + ", age=" + age + "]";
        }
        
        
    }
    View Code
    Exception in thread "main" java.io.InvalidClassException: com.datang.netty.serializabletest.Amimal; local class incompatible: stream classdesc serialVersionUID = 7643364732831133867, local class serialVersionUID = 5410859156642948805

    第二种方案显式的将生成的serialVersionUID,在这种情况下可以在修改Animal类后再次执行Run2并不会抛出异常,新增加的属性为null。

    package com.datang.netty.serializabletest;
    
    import java.io.Serializable;
    
    public class Amimal implements Serializable{
        /**
         * 
         */
        private static final long serialVersionUID = 7643364732831133867L;
        private String hobby;
        private String eat;
        private int age;
        
        private String name;
        
        
        
        public String getHobby() {
            return hobby;
        }
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
        public String getEat() {
            return eat;
        }
        public void setEat(String eat) {
            this.eat = eat;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Amimal [hobby=" + hobby + ", eat=" + eat + ", age=" + age + ", name=" + name + "]";
        }
        
        
    }
    View Code
    Amimal [hobby=打游戏, eat=鸡蛋, age=11, name=null]

    第一种方案和第二种没有太大区别只是将根据类特征生成的serialVersionUID写成了固定值1L,但是需要注意3,4两个方案虽然可以修改源类,但并不能修改serialVersionUID值,不然还是会报错。

    package com.datang.netty.serializabletest;
    
    import java.io.Serializable;
    
    public class Amimal implements Serializable{
        
        /**
         * 
         */
        private static final long serialVersionUID = 2L;
        private String hobby;
        private String eat;
        private int age;
        
        
        
        
        public String getHobby() {
            return hobby;
        }
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
        public String getEat() {
            return eat;
        }
        public void setEat(String eat) {
            this.eat = eat;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Amimal [hobby=" + hobby + ", eat=" + eat + ", age=" + age + "]";
        }
        
        
    }
    View Code
    Exception in thread "main" java.io.InvalidClassException: com.datang.netty.serializabletest.Amimal; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

    字段不参与序列化

    若类中有些字段不需要参与序列号则可以使用以下三种方式排除

    1 transient关键字

    package com.datang.netty.serializabletest;
    
    import java.io.Serializable;
    
    public class Amimal implements Serializable{
        
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private String hobby;
        private transient String eat;
        private  int age;
        
        
        
        
        public  String  getHobby() {
            return hobby;
        }
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
        public String getEat() {
            return eat;
        }
        public void setEat(String eat) {
            this.eat = eat;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Amimal [hobby=" + hobby + ", eat=" + eat + ", age=" + age + "]";
        }
        
        
    }
    View Code
    Amimal [hobby=打游戏, eat=null, age=11]

    2 static关键字

    package com.datang.netty.serializabletest;
    
    import java.io.Serializable;
    
    public class Amimal implements Serializable{
        
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private static String hobby;
        private transient String eat;
        private  int age;
        
        
        
        
        public  String  getHobby() {
            return hobby;
        }
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
        public String getEat() {
            return eat;
        }
        public void setEat(String eat) {
            this.eat = eat;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Amimal [hobby=" + hobby + ", eat=" + eat + ", age=" + age + "]";
        }
        
        
    }
    View Code
    Amimal [hobby=null, eat=null, age=11]

    serialPersistentFields数组,这种方式指定哪些需要参与序列化。

    package com.datang.netty.serializabletest;
    
    import java.io.ObjectStreamField;
    import java.io.Serializable;
    
    public class Amimal implements Serializable {
    
        /**
         * 
         */
        private static final long serialVersionUID = 1L;
        private String hobby;
        private String eat;
        private int age;
        
        private static final ObjectStreamField[] serialPersistentFields = {
                new ObjectStreamField("hobby", String.class),
                new ObjectStreamField("eat", String.class)
        };
    
        public String getHobby() {
            return hobby;
        }
    
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
    
        public String getEat() {
            return eat;
        }
    
        public void setEat(String eat) {
            this.eat = eat;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Amimal [hobby=" + hobby + ", eat=" + eat + ", age=" + age + "]";
        }
    
    }
    View Code
    Amimal [hobby=打游戏, eat=鸡蛋, age=0]

    Externalizable

    externalizable实现了Serializable接口,所以我们需要被序列化的类实现该类也可以。

    但是有两个必要条件

    1 需要被序列号的类必须有空的构造函数

    2 必须实现writeExternal和readExternal两个方法。在这两个方法内写需要被序列化的字段,需要注意的是write和read字段必须是有顺序的。

    package com.datang.netty.serializabletest;
    
    import java.io.Externalizable;
    import java.io.IOException;
    import java.io.ObjectInput;
    import java.io.ObjectOutput;
    import java.io.ObjectStreamField;
    import java.io.Serializable;
    
    public class Amimal implements Externalizable {
    
        private String hobby;
        private String eat;
        private int age;
        
        
        
    
        public Amimal() {
            
        }
    
        public String getHobby() {
            return hobby;
        }
    
        public void setHobby(String hobby) {
            this.hobby = hobby;
        }
    
        public String getEat() {
            return eat;
        }
    
        public void setEat(String eat) {
            this.eat = eat;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Amimal [hobby=" + hobby + ", eat=" + eat + ", age=" + age + "]";
        }
    
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            
            out.writeObject(hobby);
            out.writeObject(eat);
            out.writeInt(age);
        }
    
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            hobby = (String) in.readObject();
            eat = (String) in.readObject();
            age = in.readInt();
        }
    
    }
    View Code

    序列化的应用

    序列化和反序列化在Java中的一个应用场景就是深拷贝,详情可以查看我的另一篇博客。

    https://www.cnblogs.com/zumengjie/p/12198362.html

     

     

  • 相关阅读:
    从零开始搭建Wpf基础9-使用MaterialDesignToolkit对界面进行美化下
    从零开始搭建Wpf基础8-登录界面成功后显示主窗体
    从零开始搭建Wpf基础7-Api数据接入
    从零开始搭建Wpf基础6-Tab选项卡MVVM实现
    Wpf下dragablz使用Prism8进行导航-3
    从零开始搭建Wpf基础5-无限级菜单MVVM实现
    从零开始搭建Wpf基础篇4-使用Prism进行模块化
    从零开始搭建Wpf初学篇3-界面模块化
    手写es5和es6实现原型继承
    判断类型(通用类型检测方法)和手写深拷贝
  • 原文地址:https://www.cnblogs.com/zumengjie/p/14859168.html
Copyright © 2011-2022 走看看