Java学习-io-dataStream

对于 java.io.DataInputStream和DataOutputStream 一般利用当前操作可以实现对象深度拷贝; 但这其中利用到了 Serializable

对于 DataInputStream#readObject 和 DataOurputStream#writeObject 在操作过程中针对实现了Serializable 接口的数据,会进行特殊的处理,特殊点就在于 会判断操作类中是否存在 对应的 writeObject和readObject方法,如果存在则通过反射调用操作类中的方法;

 

对于 Serializable 一般会和 transient 关键字搭配在一起,原因在于,对于被transient 关键字修饰的属性,在序列化过程中不会将其进行序列化操作;

例如:

java中 java.util.ArrayList#elementData


/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access

    /**
     * Save the state of the <tt>ArrayList</tt> instance to a stream (that
     * is, serialize it).
     *
     * @serialData The length of the array backing the <tt>ArrayList</tt>
     *             instance is emitted (int), followed by all of its elements
     *             (each an <tt>Object</tt>) in the proper order.
     */
    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    /**
     * Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,
     * deserialize it).
     */
    private void readObject(java.io.ObjectInputStream s)
        throws java.io.IOException, ClassNotFoundException {
        elementData = EMPTY_ELEMENTDATA;

        // Read in size, and any hidden stuff
        s.defaultReadObject();

        // Read in capacity
        s.readInt(); // ignored

        if (size > 0) {
            // be like clone(), allocate array based upon size not capacity
            int capacity = calculateCapacity(elementData, size);
            SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, capacity);
            ensureCapacityInternal(size);

            Object[] a = elementData;
            // Read in all elements in the proper order.
            for (int i=0; i<size; i++) {
                a[i] = s.readObject();
            }
        }
    }

"TALK IS CHEAP , SHOW ME THE CODE"

/*
 * Copyright (c) 2020, guoxing, Co,. Ltd. All Rights Reserved
 */
package com.xingguo.io.operate;

import java.io.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * ObjectStreamDemo
 * {@link java.io.ObjectOutputStream}
 * {@link java.io.ObjectInputStream}
 * 一般利用此操作支持对象序列化操作
 *
 * @author guoxing
 * @date 2020/12/5 7:16 PM
 * @since
 */
public class ObjectStreamDemo {
    public static void main(String[] args) throws Exception {
        /**
         * 以 {@link java.util.ArrayList}为例
         * {@link java.io.Externalizable}
         * {@link java.io.Serializable}
         */
        ArrayList<Integer> integers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
        File file = new File("integers.ser");
        // 序列化
        try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(file))) {
            // 对于当前写入方法,在执行时会判断当前序列化数据类型是否实现了{@link java.io.Serializable}如果实现了,则根据反射判断当前类是否存在writeObject方法,如果存在对应的方法,则利用已存在的方法执行序列化操作
            /**
             * 对于 {@link java.util.ArrayList} 序列化操作, 对于 {@link ArrayList#elementData} 使用了 transient,因此在执行序列化操作时当前字段不会被直接序列化存储
             * 但在 {@link ArrayList#writeObject(java.io.ObjectOutputStream)}自定义序列化操作时,其并不直接序列化操作Objet[] ,如果直接序列化当前字段需要保存多个数据,首先是Object类型,其次是数组类型包含长度等数据,最后才是数组中的每个元素; 对于以上的操作实际会浪费一些序列化的性能,因此当前操作优化了当前操作,对于 {@link ArrayList#elementData}数据的序列化操作其首先储存数组的长度,然后循环解析数组中的每个元素并保存
             */
            objectOutputStream.writeObject(integers);
            objectOutputStream.flush();
        }

        // 反序列化
        try (ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(file))) {
            /**
             * 在反序列化操作时实际是利用的{@link ArrayList#readObject(java.io.ObjectInputStream)}
             * 其首先根据序列化文件中保存了类描述信息,以及对象的数据信息,先将其反序列化为ArrayList对象,此时对于{@link ArrayList#elementData} 已初始化完成,但数组中具体的元素还尚未完全反序列化,此时通过直接反序列化(类似于深度copy)每个元素,将其写入到数组中,实现完全的反序列化
             *
             * 根据此操作可以看出对于ArrayList在序列化和反序列化操作的简单优化,因此如果我们自己需要自定义序列化操作则可以通过直接实现{@link Externalizable}接口来实现 readObject和writeObject的操作
             */
            List<Integer> list = (List) objectInputStream.readObject();
            list.forEach(System.out::println);
        }
        // 删除文件
        file.delete();


    }
}

 

如果对于自定义对象也需要类似的序列化增强操作可以通过 java.io.Externalizable 接口进行增强




posted @ 2020-12-05 20:20  郭星  阅读(218)  评论(0)    收藏  举报