一 概念
- 序列化:将数据结构或对象转换成二进制串的过程。
- 反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程
序列化方案
- Serializable
注意:
1.必须要有无参构造函数
2.Serializable接口可以自定义序列化逻辑
private void writeObject(ObjectOutputStream out)
private void readObject(ObjectInputStream in)
3.自定义序列化逻辑必须一一对应
4.反序列化对象不是通过自身无参构造函数,而是通过父类即Object生成
/* @author unascribed
* @see java.io.ObjectOutputStream
* @see java.io.ObjectInputStream
* @see java.io.ObjectOutput
* @see java.io.ObjectInput
* @see java.io.Externalizable
* @since JDK1.1
*/
public interface Serializable {
}
##########Externalizable############
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
- json、xml
- Parcelable
serialVersionUID
serialVersionUID 是一个 private static final long 型 ID, 当它被印在对象上时, 它通常是 对象的哈希码,你可以使用 serialver 这个 JDK 工具来查看序列化对象的 serialVersionUID。 SerialVerionUID 用于对象的版本控制。也可以在类文件中指定 serialVersionUID。不指定 serialVersionUID的后果是,当你添加或修改类中的任何字段时, 则已序列化类将无法恢复, 因为 为新类和旧序列化对象生成的 serialVersionUID 将有所不同。Java 序列化过程依赖于正确的序 列化对象恢复状态的, ,并在序列化对象序列版本不匹配的情况下引发InvalidClassException
java.io.InvalidClassException: com.example.xuliehuademo01.demo01$User1; local class incompatible: stream classdesc serialVersionUID = 2, local class serialVersionUID = 3
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:2001)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1848)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2158)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1665)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:501)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:459)
序列化时,你希望某些成员不要序列化
瞬态 trasient 变量, 瞬态和静态变量会不会得到序列化等, 所以,如果你不希望任何字段是对象的状态的一部分, 然后声明它静态或瞬态根据你的需要, 这样 就不会是在 Java 序列化过程中被包含在内
private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
Field[] clFields = cl.getDeclaredFields();
ArrayList<ObjectStreamField> list = new ArrayList<>();
int mask = Modifier.STATIC | Modifier.TRANSIENT;//NOTICE
for (int i = 0; i < clFields.length; i++) {
if ((clFields[i].getModifiers() & mask) == 0) {
list.add(new ObjectStreamField(clFields[i], false, true));
}
}
int size = list.size();
return (size == 0) ? NO_FIELDS :
list.toArray(new ObjectStreamField[size]);
}
如果类中的一个成员未实现可序列化接口
如果尝试序列化实现可序列化的类的对象,但该对象包含对不可序列化类的引用,则在运行时将引发 不可序列化异常 NotSerializableException
如果类是可序列化的, 但其超类不是, 则反序列化后从超级类继承的实例 变量的状态如何
Java 序列化过程仅在对象层次都是可序列化结构中继续, 即实现 Java 中的可序列化接口, 并且 从超级类继承的实例变量的值将通过调用构造函数初始化, 在反序列化过程中不可序列化的超级类
是否可以自定义序列化过程, 或者是否可以覆盖 Java 中的默认序列化过程
对于序列化一个对象需调用 ObjectOutputStream.writeObject(saveThisObject), 并用 ObjectInputStream.readObject() 读取对象, 但 Java 虚拟机为你提供的还有一件事, 是定义这 两个方法。如果在类中定义这两种方法, 则 JVM 将调用这两种方法, 而不是应用默认序列化机制。 你可以在此处通过执行任何类型的预处理或后处理任务来自定义对象序列化和反序列化的行为。
在 Java 中的序列化和反序列化过程中使用哪些方法
考熟悉 readObject() 的用法、writeObject()、readExternal() 和 writeExternal()。 Java 序列化由java.io.ObjectOutputStream类完成。该类是一个筛选器流, 它封装在较低级别的 字节流中, 以处理序列化机制。要通过序列化机制存储任何对象, 我们调用 ObjectOutputStream.writeObject(savethisobject), 并反序列化该对象, 我们称之为 ObjectInputStream.readObject()方法。调用以 writeObject() 方法在 java 中触发序列化过程。 关于 readObject() 方法, 需要注意的一点很重要一点是, 它用于从持久性读取字节, 并从这些字 节创建对象, 并返回一个对象, 该对象需要类型强制转换为正确的类型
反序列化后的对象会重新调用构造函数吗?
不会, 因为是从二进制直接解析出来的. 使用的是 Object 进行接收再强转, 因此不是原来的那个对象
序列化与反序列化后的对象是什么关系?
是一个深拷贝, 前后对象的引用地址不同
Android 为什么要设计 bundle 而不是使用 HashMap 结构?
bundle 内部适用的是 ArrayMap, ArrayMap 相比 Hashmap 的优点是, 扩容方便, 每次扩容是原容量的一半, 在[百量] 级别, 通过二分法查找 key 和 value (ArrayMap 有两个数组, 一个存放 key 的 hashcode, 一个存放 key+value 的 Entry) 的效率要比 hashmap 快很多, 由于在内存中或者 Android 内部传输中一般数据量较小, 因此用 bundle 更为合适
serializableVersionUID 的作用是?
用于数据的版本控制, 如果反序列化后发现 ID 不一样, 认为不是之前序列化的对象
Android 中 intent/bundle 的通信原理以及大小限制?
Android 中的 bundle 实现了 parcelable 的序列化接口, 目的是为了在进程间进行通讯, 不同的进程共享一片固定大小的内存, parcelable 利用 parcel 对象的 read/write 方法, 对需要传递的数据进行内存读写, 因此这一块共享内存不能过大, 在利用 bundle 进行传输时, 会初始化一个 BINDER_VM_SIZE 的大小 = 1 * 1024 * 1024 - 4096 * 2, 即便通过修改 Framework 的代码, bundle 内核的映射只有 4M, 最大只能扩展到 4M.
为何 Intent 不能直接在组件间传递对象而要通过序列化机制?
因为 Activity 启动过程是需要与 AMS 交互, AMS 与 UI 进程是不同一个的, 因此进程间需要交互数据, 就必须序列化
序列化与持久化的关系和区别?
序列化是为了进程间数据交互而设计的, 持久化是为了把数据存储下来而设计的