美文网首页java
JDK序列化官方指南

JDK序列化官方指南

作者: spraysss | 来源:发表于2019-10-25 16:12 被阅读0次

    在网络中数据传输都是以字节数组传输的,而在java程序中操作的是类对象。java程序中对象到对象的传递在网络中的传输过程为:

    • 将对象序列化为字节数组发送到网络的接收方
    • 网络接收方接收到字节数组反序列化为对象

    java语言提供了一整套完成的序列化框架用于完成对象的序列化和反序列化

    Special handling is required for arrays, enum constants, and objects of type Class, ObjectStreamClass, and String. Other objects must implement either the Serializable or the Externalizable interface to be saved in or restored from a stream

    除了数组,枚举类型,ObjectStreamClassString类型,其他对象序列化必须实现SerializableExternalizable 接口

    For a Serializable class, Object Serialization can automatically save and restore fields of each class of an object and automatically handle classes that evolve by adding fields or supertypes. A serializable class can declare which of its fields are saved or restored, and write and read optional values and objects.
    For an Externalizable class, Object Serialization delegates to the class complete control over its external format and how the state of the supertype(s) is saved and restored.

    显示指定序列化字段

    默认情况下,不使用transient 修饰的字段都是可以序列化的,也可以使用如下方式显示指定序列化字段

    class List implements Serializable {
        List next;
    
        private static final ObjectStreamField[] serialPersistentFields
                     = {new ObjectStreamField("next", List.class)};
    
    }
    

    Serializable接口

    序列化和无参构造函数的关系
    1. 单一对象,无继承关系:若想实现序列化与反序列化,则必须实现序列化接口,否则报异常:NotSerializableException
    2. 对象间有继承关系,但无引用关系,若想实现序列化与反序列化,则父类必须实现序列化接口或提供无参构造函数,否则报invalidClassException
    3. 对象间有继承关系,并且有引用关系,若想实现序列化与反序列化,则父类必须实现序列化接口
      具体细节和demo可以参考这篇博客
      https://blog.csdn.net/zh15732621679/article/details/79803105
    方法
    • private void writeObject 自定义序列化
    • private void readObject 自定义反序列化
    • writeReplace
    • readResolve

    Externalizable 接口

    • writeExternal
    • readExternal
    • writeReplace
    • readResolve

    Writing to an Object Stream

    序列化今天的日期到文件

        FileOutputStream f = new FileOutputStream("tmp");
        ObjectOutput s = new ObjectOutputStream(f);
        s.writeObject("Today");
        s.writeObject(new Date());
        s.flush();
    
    • 序列化对象使用ObjectOutputwriteObject方法
    • ObjectOutputStream can be extended to customize the information about classes in the stream or to replace objects to be serialized. Refer to the annotateClass and replaceObject method descriptions for details.

    Reading from an Object Stream

    从文件中反序列化出日期

    FileInputStream in = new FileInputStream("tmp");
        ObjectInputStream s = new ObjectInputStream(in);
        String today = (String)s.readObject();
        Date date = (Date)s.readObject();
    
    • 序列化对象使用ObjectInputreadObject方法
    • ObjectInputStream can be extended to utilize customized information in the stream about classes or to replace objects that have been deserialized. Refer to the resolveClass and resolveObject method descriptions for details.

    Documenting Serializable Fields and Data for a Class

    序列化有关的java doc注解:

    • @serial
    • @serialField
    • @serialData

    demo

    public class SerdeDemo {
    
    
        static class User implements Serializable {
    
            public User(String username, String password) {
                this.username = username;
                this.password = password;
            }
    
            private String username;
            transient private String password;
    
            public String getUsername() {
                return username;
            }
    
            public void setUsername(String username) {
                this.username = username;
            }
    
            public String getPassword() {
                return password;
            }
    
            public void setPassword(String password) {
                this.password = password;
            }
    
            private void writeObject(ObjectOutputStream objectOutputStream) throws IOException {
                objectOutputStream.defaultWriteObject();
                objectOutputStream.writeObject(password);
    
            }
            private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException {
                objectInputStream.defaultReadObject();
                password=(String)objectInputStream.readObject();
            }
    
            @Override
            public String toString() {
                return "User{" +
                        "username='" + username + '\'' +
                        ", password='" + password + '\'' +
                        '}';
            }
        }
    
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            User user=new User("xiaoming","ABC123");
            ByteArrayOutputStream outputStream=new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream=new ObjectOutputStream(outputStream);
            objectOutputStream.writeObject(user);
    
            InputStream inputStream=new ByteArrayInputStream(outputStream.toByteArray());
            ObjectInputStream objectInputStream=new ObjectInputStream(inputStream);
            User user1=(User)objectInputStream.readObject();
            System.out.println(user1);
        }
    }
    

    默认行为不会序列化transient 修饰的字段,可以通过writeObject,readObject实现自定义的序列化

    参考

    https://docs.oracle.com/en/java/javase/13/docs/specs/serialization/index.html

    相关文章

      网友评论

        本文标题:JDK序列化官方指南

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