对于 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 ArrayList instance to a stream (that
* is, serialize it).
*
*@serialDataThe length of the array backing the ArrayList
* instance is emitted (int), followed by all of its elements
* (each an Object) in the proper order.*/
private voidwriteObject(java.io.ObjectOutputStream s)throwsjava.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
s.writeObject(elementData[i]);
}if (modCount !=expectedModCount) {throw newConcurrentModificationException();
}
}/*** Reconstitute the ArrayList instance from a stream (that is,
* deserialize it).*/
private voidreadObject(java.io.ObjectInputStream s)throwsjava.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
a[i]=s.readObject();
}
}
}
"TALK IS CHEAP , SHOW ME THE CODE"
/** Copyright (c) 2020, guoxing, Co,. Ltd. All Rights Reserved*/
packagecom.xingguo.io.operate;import java.io.*;importjava.util.ArrayList;importjava.util.Arrays;importjava.util.List;/*** ObjectStreamDemo
* {@linkjava.io.ObjectOutputStream}
* {@linkjava.io.ObjectInputStream}
* 一般利用此操作支持对象序列化操作
*
*@authorguoxing
* @date 2020/12/5 7:16 PM
*@since
*/
public classObjectStreamDemo {public static void main(String[] args) throwsException {/*** 以 {@linkjava.util.ArrayList}为例
* {@linkjava.io.Externalizable}
* {@linkjava.io.Serializable}*/ArrayList integers = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));
File file= new File("integers.ser");//序列化
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(newFileOutputStream(file))) {//对于当前写入方法,在执行时会判断当前序列化数据类型是否实现了{@link java.io.Serializable}如果实现了,则根据反射判断当前类是否存在writeObject方法,如果存在对应的方法,则利用已存在的方法执行序列化操作
/*** 对于 {@linkjava.util.ArrayList} 序列化操作, 对于 {@linkArrayList#elementData} 使用了 transient,因此在执行序列化操作时当前字段不会被直接序列化存储
* 但在 {@linkArrayList#writeObject(java.io.ObjectOutputStream)}自定义序列化操作时,其并不直接序列化操作Objet[] ,如果直接序列化当前字段需要保存多个数据,首先是Object类型,其次是数组类型包含长度等数据,最后才是数组中的每个元素; 对于以上的操作实际会浪费一些序列化的性能,因此当前操作优化了当前操作,对于 {@linkArrayList#elementData}数据的序列化操作其首先储存数组的长度,然后循环解析数组中的每个元素并保存*/objectOutputStream.writeObject(integers);
objectOutputStream.flush();
}//反序列化
try (ObjectInputStream objectInputStream = new ObjectInputStream(newFileInputStream(file))) {/*** 在反序列化操作时实际是利用的{@linkArrayList#readObject(java.io.ObjectInputStream)}
* 其首先根据序列化文件中保存了类描述信息,以及对象的数据信息,先将其反序列化为ArrayList对象,此时对于{@linkArrayList#elementData} 已初始化完成,但数组中具体的元素还尚未完全反序列化,此时通过直接反序列化(类似于深度copy)每个元素,将其写入到数组中,实现完全的反序列化
*
* 根据此操作可以看出对于ArrayList在序列化和反序列化操作的简单优化,因此如果我们自己需要自定义序列化操作则可以通过直接实现{@linkExternalizable}接口来实现 readObject和writeObject的操作*/List list =(List) objectInputStream.readObject();
list.forEach(System.out::println);
}//删除文件
file.delete();
}
}
如果对于自定义对象也需要类似的序列化增强操作可以通过 java.io.Externalizable接口进行增强