(从09年回到重庆过后,就一直在工作,时间长了惰性就慢慢起来了,公司的项目从09年忙到了现在,一直没有时间来梳理自己的东西,CSDN的Blog似乎都荒废了,不知道现在还能否坚持把Blog完成,希望有一个新的开始吧!如果读者有问题还是可直接发邮件到silentbalanceyh@126.com,我也仅仅只是想把看的、写的、学的东西总结起来,让自己有个比较完整的学习记录。本文主要针对Java的序列化相关知识,先不涉及XML序列化和Json序列化的内容,这部分内容以后再议。着色的目的是强调重点和关键的概念以及防止读者通篇阅读的视觉疲劳,也是个人的写作风格,不习惯的读者请见谅!)
本章目录:
1.Java中的序列化
2.序列化原理和算法——基础数据
3.深入序列化规范
4.源码分析
----ObjectStreamField
----ObjectStreamClass
----ObjectOutputStream
----ObjectInputStream
5.序列化原理和算法——面向对象
4.源码分析
【本章节的内容主要做的是源码分析,分析过程的概念性内容都是基于个人的理解,仅仅提供给读者参考,我尽可能在分析过程中保证这些概念性内容的准确性】
前边的章节已经辅助读者解读了JVM的规范以及提供了比较详细的示例,这个章节主要完成下边三个目标:
- 详细分析Java序列化中使用的几个核心类的源代码,通过其内部执行流程换一种角度来看看Java序列化的知识;
- 针对JVM的序列化规范中的一些疑点提供示例来加以证明,进行规范的深入理解;
- 提供Java序列化中和面向对象、最佳实践的相关内容
- ObjectStreamField
- ObjectStreamClass
- ObjectOutputStream
- ObjectInputStream
public class ObjectStreamField implements Comparable<Object>
compareTo:
public int compareTo(Object obj) {
ObjectStreamField other = (ObjectStreamField) obj;
boolean isPrim = isPrimitive();
if (isPrim != other.isPrimitive()) {
return isPrim ? -1 : 1;
}
return name.compareTo(other.name);
}
- 两个成员属性在比较的时候分为两个维度进行比较:基础类型的数据只能和基础类型的数据进行比较,对象类型的数据只能和对象类型的数据进行比较;
- 两个成员属性在比较的时候,最终调用的是String类型的compareTo成员函数来比较成员属性的属性名;
- 若返回-1则表示当前对象排在传入对象之前,为0则表示顺序不变,为1则表示当前对象应该排在传入对象之后;
在比较两个字段的名称进行字典序排列的时候,compareTo方法调用了isPrimitive成员函数,该成员函数的定义如下:
public boolean isPrimitive() {
char tcode = signature.charAt(0);
return ((tcode != 'L') && (tcode != '['));
}
/** field name */
private final String name;
/** canonical JVM signature of field type */
private final String signature;
/** field type (Object.class if unknown non-primitive type) */
private final Class<?> type;
/** whether or not to (de)serialize field values as unshared */
private final boolean unshared;
/** corresponding reflective field object, if any */
private final Field field;
/** offset of field value in enclosing field group */
private int offset = 0;
- name——java.lang.String
该属性描述了序列化的成员属性的名称; - signature——java.lang.String
该属性描述了JVM中成员属性的类型签名,注:成员属性的类型、类型代码、类型签名不是同一个概念,这三个概念在下文会加以区分; - type——java.lang.Class<?>
该属性描述了成员属性的类型; - unshared——boolean
该属性标识了当前成员属性是否具有“unshared”的语义,“unshared”的对象在规范的解析中提到过,这里不重复; - field——java.lang.reflect.Field
该属性描述了当前成员属性的JVM级别的元数据信息,在序列化提取成员属性的元数据信息时,会使用Java语言中的“反射”,该成员的类型是java.lang.reflect.Field; - offset——int
在序列化的过程中,当一个对象的成员属性个数超过一个时,JVM会将会把所有的成员属性打包成一个“组”来操作,而offset就是这个组中当前描述的成员属性的偏移量,上层的ObjectStreamClass在调用当前这个成员属性的时候就使用偏移量进行引用定位操作;
区分成员属性的类型、类型代码、类型签名:这三个概念这里希望读者通过其格式加以区分【以String类型为例】。
类型——Java的成员属性的类型一般对应的Java数据类型为Class<?>,它也可以使用格式“String.class”表示,如果是引用可以使用Class<String>进行定义,这是直接基于JVM级别的类型,一般这种数据会提供给JVM用来执行“反射”等操作;
Class<String> cs = String.class;
类型代码——类型代码的数据也是用于JVM判断成员属性数据类型的一种方式,但类型代码的Java数据类型是char,比如‘L’,它一般通过一个字符来判断当前的Java数据类型,序列化时它会把这个字符转换成二进制数据;
public String getName() {
return name;
}
String getSignature() {
return signature;
}
public Class<?> getType() {
return type;
}
public boolean isUnshared() {
return unshared;
}
Field getField() {
return field;
}
public int getOffset() {
return offset;
}
protected void setOffset(int offset) {
this.offset = offset;
}
两个public的构造函数内容如下:
public ObjectStreamField(String name, Class<?> type) {
this(name, type, false);
}
public ObjectStreamField(String name, Class<?> type, boolean unshared) {
if (name == null) {
throw new NullPointerException();
}
this.name = name;
this.type = type;
this.unshared = unshared;
signature = getClassSignature(type).intern();
field = null;
}
- 第一个构造函数调用了第二个构造函数的内容,其中第三个参数传入的是false,也就是说默认情况下通过两参构造ObjectStreamField的时候,构造的是一个非"unshared"的成员属性,从序列化的原理上来讲【前一章规范中已经注明】,不论是类还是字段,"unshared"的状态下JVM都会为其创建新的元数据信息,而默认情况下是共享元数据信息的,在生成二进制序列的时候并不为每一个成员属性或者类单独创建元数据信息;
- 使用public构造函数的时候,基本成员属性【字段】中,field属性的初始化值为null;而name、type、unshared都是传入的;比较特殊的属性是signature,它的初始值是使用的getClassSignature方法来获取的;
ObjectStreamField(String name, String signature, boolean unshared) {
if (name == null) {
throw new NullPointerException();
}
this.name = name;
this.signature = signature.intern();
this.unshared = unshared;
field = null;
switch (signature.charAt(0)) {
case 'Z': type = Boolean.TYPE; break;
case 'B': type = Byte.TYPE; break;
case 'C': type = Character.TYPE; break;
case 'S': type = Short.TYPE; break;
case 'I': type = Integer.TYPE; break;
case 'J': type = Long.TYPE; break;
case 'F': type = Float.TYPE; break;
case 'D': type = Double.TYPE; break;
case 'L':
case '[': type = Object.class; break;
default: throw new IllegalArgumentException("illegal signature");
}
}
ObjectStreamField(Field field, boolean unshared, boolean showType) {
this.field = field;
this.unshared = unshared;
name = field.getName();
Class<?> ftype = field.getType();
type = (showType || ftype.isPrimitive()) ? ftype : Object.class;
signature = getClassSignature(ftype).intern();
}
- 两个default域的构造函数不存在相互调用关系,和public的两个构造函数的相互调用关系不一样;
- 第一个default域的构造函数中,name、signature、unshared都是直接传入的,field直接设置为null,没有经过复杂的运算;而type使用了Java序列化中的类型代码【Type Code】的映射转换,在第三章的序列化规范中可以看到每一个成员属性都有固定的Type Code,而在构造一个ObjectStreamField的时候,其type属性的运算是根据Type Code的值来换算的;若获取的Type Code不对则直接抛出IllegalArgumentException的异常;
- 第二个default域的构造函数中,field、unshared两个成员属性是直接传入的,name属性从field中提取,而signature是通过当前传入的field的类型作为getClassSignature方法的参数计算获取;showType在这个构造函数中主要是为了序列化实现的兼容性而考虑——如果当前成员属性是一个基础类型的数据【isPrimitive方法返回true】,它将直接返回基础数据的类型;若showType传入的值也是true,那么即使不检查成员属性的类型也会返回,这种情况用于对象类型的获取。推测type运算的正常逻辑如下:
-- 如果当前字段是一个基础类型,则返回基础类型的getType的值;
-- 如果当前字段是一个自定义对象类型,则返回对象类型的getType的值;
-- 以上两者都不是的情况,返回Object.class;
private static String getClassSignature(Class<?> cl) {
StringBuilder sbuf = new StringBuilder();
while (cl.isArray()) {
sbuf.append('[');
cl = cl.getComponentType();
}
if (cl.isPrimitive()) {
if (cl == Integer.TYPE) {
sbuf.append('I');
} else if (cl == Byte.TYPE) {
sbuf.append('B');
} else if (cl == Long.TYPE) {
sbuf.append('J');
} else if (cl == Float.TYPE) {
sbuf.append('F');
} else if (cl == Double.TYPE) {
sbuf.append('D');
} else if (cl == Short.TYPE) {
sbuf.append('S');
} else if (cl == Character.TYPE) {
sbuf.append('C');
} else if (cl == Boolean.TYPE) {
sbuf.append('Z');
} else if (cl == Void.TYPE) {
sbuf.append('V');
} else {
throw new InternalError();
}
} else {
sbuf.append('L' + cl.getName().replace('.', '/') + ';');
}
return sbuf.toString();
}
package org.susan.java.serial;
import java.util.ArrayList;
import java.util.List;
public class FieldSignature {
public static String getClassSignature(Class<?> cl) {
StringBuilder sbuf = new StringBuilder();
while (cl.isArray()) {
sbuf.append('[');
cl = cl.getComponentType();
}
if (cl.isPrimitive()) {
if (cl == Integer.TYPE) {
sbuf.append('I');
} else if (cl == Byte.TYPE) {
sbuf.append('B');
} else if (cl == Long.TYPE) {
sbuf.append('J');
} else if (cl == Float.TYPE) {
sbuf.append('F');
} else if (cl == Double.TYPE) {
sbuf.append('D');
} else if (cl == Short.TYPE) {
sbuf.append('S');
} else if (cl == Character.TYPE) {
sbuf.append('C');
} else if (cl == Boolean.TYPE) {
sbuf.append('Z');
} else if (cl == Void.TYPE) {
sbuf.append('V');
} else {
throw new InternalError();
}
} else {
sbuf.append('L' + cl.getName().replace('.', '/') + ';');
}
return sbuf.toString();
}
public static void main(String args[]){
// void类型
System.out.println(FieldSignature.getClassSignature(void.class));
// 基础类型
System.out.println(FieldSignature.getClassSignature(int.class));
// 基础封装类型
System.out.println(FieldSignature.getClassSignature(Integer.class));
// 自定义对象类型
System.out.println(FieldSignature.getClassSignature(FieldSignature.class));
// String类型
System.out.println(FieldSignature.getClassSignature(String.class));
// 数组类型
int[] arr = new int[2];
System.out.println(FieldSignature.getClassSignature(arr.getClass()));
// 对象数组
FieldSignature[] signs = new FieldSignature[4];
System.out.println(FieldSignature.getClassSignature(signs.getClass()));
// 对象集合
List<FieldSignature> list = new ArrayList<FieldSignature>();
System.out.println(FieldSignature.getClassSignature(list.getClass()));
}
}
I
Ljava/lang/Integer;
Lorg/susan/java/serial/FieldSignature;
Ljava/lang/String;
[I
[Lorg/susan/java/serial/FieldSignature;
Ljava/util/ArrayList;
- Java中有一个特殊的Class类型——Void.class,这个Class的构造函数是私有的,所以它不具有实例,除了上边的void.class【Void.class等价】可以直接使用,而成员属性是不具有这个类型的;但是这里的解析仅仅只涉及了成员属性的签名,没有涉及成员函数的签名,成员函数的签名中函数的返回值是可以返回void类型的,也就是它的返回值类型可以是Void.class。
- 所有的基础数据类型,其类型签名就是一个固定的字符串,类似:I、B、J、F、D、S、C、Z等,如果基础类型的成员属性不属于上述八种类型中的任何一种,同样也不是V表示的void类型,则抛出InternalError的错误;
- 所有的数组使用的签名第一个字符为[符号,紧随其后的是数组中元素的类型签名, 对比上边的arr数组和signs数组的签名,它们一个是int[]类型,另外一个是FieldSignature[]的类型,看看输出就知道其元素签名的区别;从区别中可以知道的是所有对象数组的签名也具有唯一性,它的类型签名的前缀为[L;
- 所有的对象签名都是以L开始,后边跟上一个固定格式来描述该对象的类型,这个固定格式一般是对象的类全名替换'.'为‘/’,然后加上';'的后缀;
- 最后有一点容易忽略:只要是非基础类型【包括非基础类型的数组】,其签名的末尾都会有分号作为结束标识;
public char getTypeCode() {
return signature.charAt(0);
}
public String getTypeString() {
return isPrimitive() ? null : signature;
}
prim_typecode fieldName
obj_typecode fieldName className1
public class ObjectStreamClass implements Serializable
private static class Caches
private static class ExceptionInfo
private static class EntryFuture
static class ClassDataSlot
private static class MemberSignature
private static class FieldReflector
private static class FieldReflectorKey extends WeakReference<Class<?>>
static class WeakClassKey extends WeakReference<Class<?>>
private static class Caches {
/** cache mapping local classes -> descriptors */
static final ConcurrentMap<WeakClassKey,Reference<?>> localDescs =
new ConcurrentHashMap<>();
/** cache mapping field group/local desc pairs -> field reflectors */
static final ConcurrentMap<FieldReflectorKey,Reference<?>> reflectors =
new ConcurrentHashMap<>();
/** queue for WeakReferences to local classes */
private static final ReferenceQueue<Class<?>> localDescsQueue =
new ReferenceQueue<>();
/** queue for WeakReferences to field reflectors keys */
private static final ReferenceQueue<Class<?>> reflectorsQueue =
new ReferenceQueue<>();
}
localDescs和reflectors的两个成员是默认default域的静态成员,类型为“哈希表映射”,同样也加入了final修饰,也就是说这两个成员同样具有JVM级别的唯一性,不仅仅如此,这两个成员充当了缓存的作用;localDescs成员的哈希表键为一个WeakClassKey类型,它的值为一个抽象类型Reference<?>,这个抽象类为SoftReference【软引用】和WeakReference【弱引用】的父类,它指向了WeakClassKey对应的类描述符对象;reflectors成员的哈希表键为FieldReflectorKey类型,它的值同样为一个抽象类型Reference<?>,它指向了FieldReflectorKey对应的字段描述信息。
结合上边的定义,这四个成员可以用下边的图进行结构解析,希望读者理解Caches中四个成员的关系:
【*:Caches类定义了两部分内容:第一部分是和类描述信息有关的,第二部分是和字段信息有关的,这两部分内容各自包含了一个队列容器和哈希表,它们都具有唯一性。至于为什么使用软引用、弱引用在后边分析的时候希望可以给出答案。使用ConcurrentMap的目的是为了保证序列化时的性能、可伸缩性以及并发操作】。
简单提及一下ConcurrentMap的知识点:
ConcurrentMap的主要子类是ConcurrentHashMap,该对象中包含了多个segment,而每一个segment中都包含了一个Entity的数组,而它的使用过程中比普通的HashMap多了一个segment类,segment类继承于ReentrantLock类,也就是说它实际上是一个锁。当多个线程操作ConcurrentHashMap时,JVM不会完全锁住这个map,而是锁住一个segment,这种情况下就提高了并发的效率。它的优缺点:
优点——由于是对对应的segment加锁,不是锁定整个map,并发性得到提高,能够直接提高插入、检索以及移除操作的可伸缩性;
缺点——当遍历map中的元素时,需要获取所有segment的锁,使用遍历会很慢。锁的增多占用了系统的资源,当调用针对整个集合的方法,比如isEmpty或size的实现更加困难,而且结果可能会有错误的风险。
该类中只包含了一个异常类的基本类名和异常信息,它的完整定义如下:
private static class ExceptionInfo {
private final String className;
private final String message;
ExceptionInfo(String cn, String msg) {
className = cn;
message = msg;
}
/**
* Returns (does not throw) an InvalidClassException instance created
* from the information in this object, suitable for being thrown by
* the caller.
*/
InvalidClassException newInvalidClassException() {
return new InvalidClassException(className, message);
}
}
private static class EntryFuture {
private static final Object unset = new Object();
private final Thread owner = Thread.currentThread();
private Object entry = unset;
/**
* Attempts to set the value contained by this EntryFuture. If the
* EntryFuture's value has not been set already, then the value is
* saved, any callers blocked in the get() method are notified, and
* true is returned. If the value has already been set, then no saving
* or notification occurs, and false is returned.
*/
synchronized boolean set(Object entry) {
if (this.entry != unset) {
return false;
}
this.entry = entry;
notifyAll();
return true;
}
/**
* Returns the value contained by this EntryFuture, blocking if
* necessary until a value is set.
*/
synchronized Object get() {
boolean interrupted = false;
while (entry == unset) {
try {
wait();
} catch (InterruptedException ex) {
interrupted = true;
}
}
if (interrupted) {
AccessController.doPrivileged(
new PrivilegedAction<Void>() {
public Void run() {
Thread.currentThread().interrupt();
return null;
}
}
);
}
return entry;
}
/**
* Returns the thread that created this EntryFuture.
*/
Thread getOwner() {
return owner;
}
}
【*:在分析ObjectStreamClass源代码之前,先解析里面的Class定义,其目的是为了知道ObjectStreamClass中拥有多少内部类,从这些内部类的定义可以知道它们大部分的修饰符都是private的,所以只能在ObjectStreamClass中使用,了解了它们过后分析ObjectStreamClass就相对简单许多。】
static class ClassDataSlot {
/** class descriptor "occupying" this slot */
final ObjectStreamClass desc;
/** true if serialized form includes data for this slot's descriptor */
final boolean hasData;
ClassDataSlot(ObjectStreamClass desc, boolean hasData) {
this.desc = desc;
this.hasData = hasData;
}
}
private static class MemberSignature {
public final Member member;
public final String name;
public final String signature;
public MemberSignature(Field field) {
member = field;
name = field.getName();
signature = getClassSignature(field.getType());
}
public MemberSignature(Constructor cons) {
member = cons;
name = cons.getName();
signature = getMethodSignature(
cons.getParameterTypes(), Void.TYPE);
}
public MemberSignature(Method meth) {
member = meth;
name = meth.getName();
signature = getMethodSignature(
meth.getParameterTypes(), meth.getReturnType());
}
}
public MemberSignature(Field field)
public MemberSignature(Constructor cons)
public MemberSignature(Method meth)
Constructor和Method单参数构造函数都调用了私有成员函数getMethodSignature,先看看这个函数的定义:
private static String getMethodSignature(Class<?>[] paramTypes,
Class<?> retType)
{
StringBuilder sbuf = new StringBuilder();
sbuf.append('(');
for (int i = 0; i < paramTypes.length; i++) {
sbuf.append(getClassSignature(paramTypes[i]));
}
sbuf.append(')');
sbuf.append(getClassSignature(retType));
return sbuf.toString();
}
package org.susan.java.serial;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class MethodSignature {
public static String getMethodSignature(Class<?>[] paramTypes,
Class<?> retType) {
StringBuilder sbuf = new StringBuilder();
sbuf.append('(');
for (int i = 0; i < paramTypes.length; i++) {
sbuf.append(FieldSignature.getClassSignature(paramTypes[i]));
}
sbuf.append(')');
sbuf.append(FieldSignature.getClassSignature(retType));
return sbuf.toString();
}
public static void main(String args[]){
// 构造函数签名
Constructor<?>[] cons = MethodTest.class.getDeclaredConstructors();
for( Constructor<?> con: cons){
System.out.println("==>" + con.getName());
System.out.println(getMethodSignature(con.getParameterTypes(),Void.TYPE));
}
// 方法签名
Method[] methods = MethodTest.class.getDeclaredMethods();
for( Method method: methods){
System.out.println("==>" + method.getName());
System.out.println(getMethodSignature(method.getParameterTypes(),method.getReturnType()));
}
}
}
class MethodTest{
private int age;
private String name;
public MethodTest(int age, String name){
this.age = age;
this.name = name;
}
public MethodTest(int age){
this(age,"Unknown");
}
public String buildTemplate(String prefix){
return prefix + " " + this.name + ", you are " + this.age + " now.";
}
public void buildHello(){
String template = buildTemplate("Hello");
System.out.println(template);
}
}
(ILjava/lang/String;)V
==>org.susan.java.serial.MethodTest
(I)V
==>buildHello
()V
==>buildTemplate
(Ljava/lang/String;)Ljava/lang/String;
FieldRelfectorKey的定义如下:
private static class FieldReflectorKey extends WeakReference<Class<?>> {
private final String sigs;
private final int hash;
private final boolean nullClass;
FieldReflectorKey(Class<?> cl, ObjectStreamField[] fields,
ReferenceQueue<Class<?>> queue)
{
super(cl, queue);
nullClass = (cl == null);
StringBuilder sbuf = new StringBuilder();
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i];
sbuf.append(f.getName()).append(f.getSignature());
}
sigs = sbuf.toString();
hash = System.identityHashCode(cl) + sigs.hashCode();
}
public int hashCode() {
return hash;
}
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof FieldReflectorKey) {
FieldReflectorKey other = (FieldReflectorKey) obj;
Class<?> referent;
return (nullClass ? other.nullClass
: ((referent = get()) != null) &&
(referent == other.get())) &&
sigs.equals(other.sigs);
} else {
return false;
}
}
}
- 调用父类WeakReference的构造函数;
- 如果传入的第一个参数cl为null,则将成员函数nullClass设置成true,该成员函数是一个标识,判断传入的类是否为null;
- 分析第二个参数fields生成传入Class的整体字段签名;
- 将整体字段签名赋值给成员属性sigs;
- 计算签名过后的hash值,根据传入的Class的hashCode以及签名sigs的hashCode计算;
static class WeakClassKey extends WeakReference<Class<?>> {
/**
* saved value of the referent's identity hash code, to maintain
* a consistent hash code after the referent has been cleared
*/
private final int hash;
/**
* Create a new WeakClassKey to the given object, registered
* with a queue.
*/
WeakClassKey(Class<?> cl, ReferenceQueue<Class<?>> refQueue) {
super(cl, refQueue);
hash = System.identityHashCode(cl);
}
/**
* Returns the identity hash code of the original referent.
*/
public int hashCode() {
return hash;
}
/**
* Returns true if the given object is this identical
* WeakClassKey instance, or, if this object's referent has not
* been cleared, if the given object is another WeakClassKey
* instance with the identical non-null referent as this one.
*/
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj instanceof WeakClassKey) {
Object referent = get();
return (referent != null) &&
(referent == ((WeakClassKey) obj).get());
} else {
return false;
}
}
}
/** handle for performing unsafe operations */
private static final Unsafe unsafe = Unsafe.getUnsafe();
/** fields to operate on */
private final ObjectStreamField[] fields;
/** number of primitive fields */
private final int numPrimFields;
/** unsafe field keys for reading fields - may contain dupes */
private final long[] readKeys;
/** unsafe fields keys for writing fields - no dupes */
private final long[] writeKeys;
/** field data offsets */
private final int[] offsets;
/** field type codes */
private final char[] typeCodes;
/** field types */
private final Class<?>[] types;
- unsafe——sun.misc.Unsafe
该成员主要用于处理一些不安全的操作,这个操作偏向于CAS硬件原语级别【后边会讲到】,而不是单纯的Java语言级的内容; - fields——java.io.ObjectStreamField[]
fields成员用于描述当前的ObjectStreamClass中的成员属性描述集合,前边已经讲过ObjectStreamField类可以分析成员属性得到它对应的元数据信息,而fields成员属性保存了当前分析的类对应的所有成员属性的元数据信息,它是一个数组结构,每一个元素都对应了成员属性的元数据描述信息,且不会重复。 - numPrimFIelds——int
该属性描述了当前ObjectStreamClass中基础类型的成员属性的数量;
- readKeys——long[]
针对不安全的字段的读取提供的键值,这个键值可能包含了重复值【CAS原语级别】; - writeKeys——long[]
针对不安全的字段的写入提供的键值,这个键值不包含重复值【CAS原语级别】; - offsets——int[]
前边在分析ObjectStreamField的时候讲过,在序列化分析一个类中定义的成员属性的时候,依靠偏移量来读取每一个成员属性,而FieldReflector是针对当前Class的所有成员属性进行分析的类,所以它会有一个偏移量的集合,offsets就是保存偏移量的数组; - typeCodes——char[]
typeCodes数组包含了一个Class中所有成员属性的类型代码的集合; - types——java.lang.Class<?>[]
types数组包含了一个Class中所有成员属性的类型的集合;
在FieldReflector类中包含了一个getFields方法,用于获取所有的字段元数据信息【ObjectStreamField[]类型】,它的定义如下:
ObjectStreamField[] getFields() {
return fields;
}
void getPrimFieldValues(Object obj, byte[] buf) {...}
void setPrimFieldValues(Object obj, byte[] buf) {...}
void getObjFieldValues(Object obj, Object[] vals) {...}
void setObjFieldValues(Object obj, Object[] vals) {...}
setPrimFieldValues方法是对应get方法的逆方法,它主要用于基础类型字段的反序列化操作,它会先从writeKeys中去获取字段对应的键值,如果出现了Unsafe.INVALID_FIELD_OFFSET的键值直接放弃该字段的设置行为。这个方法会使用writeKeys、offsets、typeCodes成员,它主要用于将读取的字节数据写入到当前传入的对象中,设置该对象对应的成员属性的值;
getObjFieldValues方法和setObjFieldValues方法在这里就不重复了,它们和上边提到的两个方法的用法是一致的,唯一的不同是它们的操作对象是Java中的对象类型的字段而不是基础类型的字段;
注意这里的writeKeys和readKeys方法,从前文中读者可以知道一般写操作是:把Java对象的状态转换成字节流,而读操作是:把字节流中的数据恢复成Java对象。但从源代码中可以知道这里的读写概念相反,writeKeys负责将字节流中的数据写入到Java对象,而readKeys负责将Java对象中的字段值读取出来反向写入到字节流中;为什么会这样呢?因为操作对象不一样,前文提到的序列化反序列化的操作对象是目标介质比如文件,而这里的writeKeys和readKeys的操作对象是Java对象,因为它们的操作对象刚好是“逆向”的,所以才会出现这样的的情况,请读者仔细分析理解。
这里还有一个容易混淆的内容是sun.misc.Unsafe类,简单讲讲这个类的作用以及代码中出现的INVALID_FIELD_OFFSET的含义:
参考:http://en.wikipedia.org/wiki/Compare-and-swap
CAS【Compare And Swap】——简单讲它表示比较并交换的算法,属于计算机原子级别的操作,主要用于处理器支持并发提供的原子级操作的测试,通常在计算机的位级别运行该操作,CAS操作包含了三个操作数:内存位置(V)、预期原值(A)和新值(B)。如果内存位置的值与预期原值相匹配,则处理器会自动将该位置的值更新成新值,否则处理器不做任何操作。无论哪种情况它都会在CAS指令之前返回该内存位置的值,一些特殊情况下它会返回CAS是否成功的标记,而不会提取这个位置的值。CAS有效地说明了“我认为位置V应该包含值A,如果包含该值则将B放到这个位置,否则不去更改该位置,只是告诉自己这个位置现在的值即可。”
CAS用于同步方式的时候,会从地址V读取值A、执行多步计算来获得新值B,然后使用CAS将V的值从A更新为B,如果V处的值没有同时更改,则CAS操作成功。类似于CAS的指令允许算法执行读-修改-写操作,而不需要害怕其他线程同时修改变量,因为如果其他线程修改变量则CAS会检测它并且失败,该算法可以对操作重新计算。CAS最大的价值是可以在硬件中实现,并且在大多数处理器中是一种轻量级的实现。
Java的并发包java.util.concurrent中大量使用了CAS操作,而涉及到并发的地方都会去调用Unsafe类,也就是说Java语言中针对CAS原子级别的操作都使用sun.misc.Unsafe类实现,这个类中包含了许多native的方法,而且是未开源的,这里就不去了解Unsafe类的源代码了。INVALID_FIELD_OFFSET的值为-1,实际上Java在底层访问一个类的时候,它在调用成员属性时都是用偏移量操作的,而类定义中的第一个字段偏移量应该是0,如果一个类中的字段不匹配或者找不到的情况就返回INVALID_FIELD_OFFSET,即返回-1告诉JVM针对当前这个类执行的字段操作是不合法的。
FieldReflector(ObjectStreamField[] fields) {
this.fields = fields;
int nfields = fields.length;
readKeys = new long[nfields];
writeKeys = new long[nfields];
offsets = new int[nfields];
typeCodes = new char[nfields];
ArrayList<Class<?>> typeList = new ArrayList<>();
Set<Long> usedKeys = new HashSet<>();
for (int i = 0; i < nfields; i++) {
ObjectStreamField f = fields[i];
Field rf = f.getField();
long key = (rf != null) ?
unsafe.objectFieldOffset(rf) : Unsafe.INVALID_FIELD_OFFSET;
readKeys[i] = key;
writeKeys[i] = usedKeys.add(key) ?
key : Unsafe.INVALID_FIELD_OFFSET;
offsets[i] = f.getOffset();
typeCodes[i] = f.getTypeCode();
if (!f.isPrimitive()) {
typeList.add((rf != null) ? rf.getType() : null);
}
}
types = typeList.toArray(new Class<?>[typeList.size()]);
numPrimFields = nfields - types.length;
}
private static native void initNative();
static {
initNative();
}
private native static boolean hasStaticInitializer(Class<?> cl);
hasStaticInitializer方法主要用于检测传入的类中是否包含了静态初始化方法,如果包含则返回true,反之直接返回false;而initNative()方法的目的就是执行本地方法的“实现初始化”操作,ObjectStreamClass类中的静态初始化块static{}中的内容就是执行initNative()方法【该方法会在ClassLoader载入Java的Class的时候调用initNative方法】——实际上这个地方的initNative方法调用过后,系统底层才会把hasStaticInitializer方法的实现代码初始化,如果不调用initNative方法,当系统在调用hasStaticInitializer方法的时候会因为该方法的实现代码没有初始化而失败,根据Java的语言规定native的方法实现需要使用C语言,所以这里的initNative方法应该是把C语言的实现代码初始化——不过这一切都是我个人的理解,关于这个方法确实没有证据来证明,本文的目的是透析Java序列化,关于native的使用这里就不多说了。
private static final long serialVersionUID = -6120832682080437368L;
/** serialVersionUID of represented class (null if not computed yet) */
private volatile Long suid;
public long getSerialVersionUID() {
// REMIND: synchronize instead of relying on volatile?
if (suid == null) {
suid = AccessController.doPrivileged(
new PrivilegedAction<Long>() {
public Long run() {
return computeDefaultSUID(cl);
}
}
);
}
return suid.longValue();
}
private static Long getDeclaredSUID(Class<?> cl) {
try {
Field f = cl.getDeclaredField("serialVersionUID");
int mask = Modifier.STATIC | Modifier.FINAL;
if ((f.getModifiers() & mask) == mask) {
f.setAccessible(true);
return Long.valueOf(f.getLong(null));
}
} catch (Exception ex) {
}
return null;
}
private static long computeDefaultSUID(Class<?> cl) {
if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl))
{
return 0L;
}
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
dout.writeUTF(cl.getName());
int classMods = cl.getModifiers() &
(Modifier.PUBLIC | Modifier.FINAL |
Modifier.INTERFACE | Modifier.ABSTRACT);
/*
* compensate for javac bug in which ABSTRACT bit was set for an
* interface only if the interface declared methods
*/
Method[] methods = cl.getDeclaredMethods();
if ((classMods & Modifier.INTERFACE) != 0) {
classMods = (methods.length > 0) ?
(classMods | Modifier.ABSTRACT) :
(classMods & ~Modifier.ABSTRACT);
}
dout.writeInt(classMods);
if (!cl.isArray()) {
/*
* compensate for change in 1.2FCS in which
* Class.getInterfaces() was modified to return Cloneable and
* Serializable for array classes.
*/
Class<?>[] interfaces = cl.getInterfaces();
String[] ifaceNames = new String[interfaces.length];
for (int i = 0; i < interfaces.length; i++) {
ifaceNames[i] = interfaces[i].getName();
}
Arrays.sort(ifaceNames);
for (int i = 0; i < ifaceNames.length; i++) {
dout.writeUTF(ifaceNames[i]);
}
}
Field[] fields = cl.getDeclaredFields();
MemberSignature[] fieldSigs = new MemberSignature[fields.length];
for (int i = 0; i < fields.length; i++) {
fieldSigs[i] = new MemberSignature(fields[i]);
}
Arrays.sort(fieldSigs, new Comparator<MemberSignature>() {
public int compare(MemberSignature ms1, MemberSignature ms2) {
return ms1.name.compareTo(ms2.name);
}
});
for (int i = 0; i < fieldSigs.length; i++) {
MemberSignature sig = fieldSigs[i];
int mods = sig.member.getModifiers() &
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE |
Modifier.TRANSIENT);
if (((mods & Modifier.PRIVATE) == 0) ||
((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0))
{
dout.writeUTF(sig.name);
dout.writeInt(mods);
dout.writeUTF(sig.signature);
}
}
if (hasStaticInitializer(cl)) {
dout.writeUTF("<clinit>");
dout.writeInt(Modifier.STATIC);
dout.writeUTF("()V");
}
Constructor[] cons = cl.getDeclaredConstructors();
MemberSignature[] consSigs = new MemberSignature[cons.length];
for (int i = 0; i < cons.length; i++) {
consSigs[i] = new MemberSignature(cons[i]);
}
Arrays.sort(consSigs, new Comparator<MemberSignature>() {
public int compare(MemberSignature ms1, MemberSignature ms2) {
return ms1.signature.compareTo(ms2.signature);
}
});
for (int i = 0; i < consSigs.length; i++) {
MemberSignature sig = consSigs[i];
int mods = sig.member.getModifiers() &
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.STATIC | Modifier.FINAL |
Modifier.SYNCHRONIZED | Modifier.NATIVE |
Modifier.ABSTRACT | Modifier.STRICT);
if ((mods & Modifier.PRIVATE) == 0) {
dout.writeUTF("<init>");
dout.writeInt(mods);
dout.writeUTF(sig.signature.replace('/', '.'));
}
}
MemberSignature[] methSigs = new MemberSignature[methods.length];
for (int i = 0; i < methods.length; i++) {
methSigs[i] = new MemberSignature(methods[i]);
}
Arrays.sort(methSigs, new Comparator<MemberSignature>() {
public int compare(MemberSignature ms1, MemberSignature ms2) {
int comp = ms1.name.compareTo(ms2.name);
if (comp == 0) {
comp = ms1.signature.compareTo(ms2.signature);
}
return comp;
}
});
for (int i = 0; i < methSigs.length; i++) {
MemberSignature sig = methSigs[i];
int mods = sig.member.getModifiers() &
(Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED |
Modifier.STATIC | Modifier.FINAL |
Modifier.SYNCHRONIZED | Modifier.NATIVE |
Modifier.ABSTRACT | Modifier.STRICT);
if ((mods & Modifier.PRIVATE) == 0) {
dout.writeUTF(sig.name);
dout.writeInt(mods);
dout.writeUTF(sig.signature.replace('/', '.'));
}
}
dout.flush();
MessageDigest md = MessageDigest.getInstance("SHA");
byte[] hashBytes = md.digest(bout.toByteArray());
long hash = 0;
for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) {
hash = (hash << 8) | (hashBytes[i] & 0xFF);
}
return hash;
} catch (IOException ex) {
throw new InternalError();
} catch (NoSuchAlgorithmException ex) {
throw new SecurityException(ex.getMessage());
}
}
- 先判断当前类是否实现了Serializable接口,如果一个类没有实现了Serializable接口或者是一个动态代理类,则suid的值为0L;
if (!Serializable.class.isAssignableFrom(cl) || Proxy.isProxyClass(cl)) { return 0L; }
- 【1】生成suid的时候,先写入类名,写入的时候以字节方式写入,如果是字符串则使用UTF-8的方式编码;
ByteArrayOutputStream bout = new ByteArrayOutputStream(); dout.writeUTF(cl.getName());
- 【2】然后写入类的修饰符,使用的是一个32-bit的整数,classMods的计算会先进行计算,提取内容修饰符是public、final、interface、abstract的,至于下边代码后半部分代码在注释中有说明是为了处理javac编译的一个bug而存在;
int classMods = cl.getModifiers() & (Modifier.PUBLIC | Modifier.FINAL | Modifier.INTERFACE | Modifier.ABSTRACT); /* * compensate for javac bug in which ABSTRACT bit was set for an * interface only if the interface declared methods */ Method[] methods = cl.getDeclaredMethods(); if ((classMods & Modifier.INTERFACE) != 0) { classMods = (methods.length > 0) ? (classMods | Modifier.ABSTRACT) : (classMods & ~Modifier.ABSTRACT); } dout.writeInt(classMods);
- 【3】按照字典序排列所有实现接口的名称,将这个接口名称写入字节数组,排序使用的方法为Arrays.sort方法,这里会根据cl的getInterfaces方法获取所有当前类实现的接口集,然后通过遍历的方式构造一个按照字典序排列的接口名称数组;
if (!cl.isArray()) { /* * compensate for change in 1.2FCS in which * Class.getInterfaces() was modified to return Cloneable and * Serializable for array classes. */ Class<?>[] interfaces = cl.getInterfaces(); String[] ifaceNames = new String[interfaces.length]; for (int i = 0; i < interfaces.length; i++) { ifaceNames[i] = interfaces[i].getName(); } Arrays.sort(ifaceNames); for (int i = 0; i < ifaceNames.length; i++) { dout.writeUTF(ifaceNames[i]); } }
- 【4】针对类定义中的每一个字段按字典序写入,写入的时候会先写入字段的名称,然后写入32位整数的字段修饰符,最后写入该字段的签名信息,这个地方会使用MemberSignature类用来分析成员属性的信息;在写入的时候会排除static和transient的字段。注意循环内的判断条件——计算mods时,mods对Member的修饰进行了两次运算,第一次提取修饰符为public、private、protected、static、final、volatile、transient的内容,然后再判断去掉private、static和transient的内容【注意private关键字的出现表示这里提取的信息是非私有的信息】;
Field[] fields = cl.getDeclaredFields(); MemberSignature[] fieldSigs = new MemberSignature[fields.length]; for (int i = 0; i < fields.length; i++) { fieldSigs[i] = new MemberSignature(fields[i]); } Arrays.sort(fieldSigs, new Comparator<MemberSignature>() { public int compare(MemberSignature ms1, MemberSignature ms2) { return ms1.name.compareTo(ms2.name); } }); for (int i = 0; i < fieldSigs.length; i++) { MemberSignature sig = fieldSigs[i]; int mods = sig.member.getModifiers() & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | Modifier.VOLATILE | Modifier.TRANSIENT); if (((mods & Modifier.PRIVATE) == 0) || ((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) { dout.writeUTF(sig.name); dout.writeInt(mods); dout.writeUTF(sig.signature); } }
- 【5】如果当前类中存在静态初始化操作,则写入静态初始化的信息,这里可以看到静态初始化的描述符:JVM序列化规范中提及的<clinit>段;
if (hasStaticInitializer(cl)) { dout.writeUTF("<clinit>"); dout.writeInt(Modifier.STATIC); dout.writeUTF("()V"); }
- 【6】针对非私有的构造函数,写入方法名、方法修饰符和方法签名,这里可以看到构造函数初始化的描述符:JVM序列化规范中提及的<init>段——注意方法必须是非私有的,去掉了PRIVATE的内容;
Constructor[] cons = cl.getDeclaredConstructors(); MemberSignature[] consSigs = new MemberSignature[cons.length]; for (int i = 0; i < cons.length; i++) { consSigs[i] = new MemberSignature(cons[i]); } Arrays.sort(consSigs, new Comparator<MemberSignature>() { public int compare(MemberSignature ms1, MemberSignature ms2) { return ms1.signature.compareTo(ms2.signature); } }); for (int i = 0; i < consSigs.length; i++) { MemberSignature sig = consSigs[i]; int mods = sig.member.getModifiers() & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.ABSTRACT | Modifier.STRICT); if ((mods & Modifier.PRIVATE) == 0) { dout.writeUTF("<init>"); dout.writeInt(mods); dout.writeUTF(sig.signature.replace('/', '.')); } }
- 【7】针对非私有成员方法,写入方法名、方法修饰符、方法签名,和上一步的逻辑基本相同;
MemberSignature[] methSigs = new MemberSignature[methods.length]; for (int i = 0; i < methods.length; i++) { methSigs[i] = new MemberSignature(methods[i]); } Arrays.sort(methSigs, new Comparator<MemberSignature>() { public int compare(MemberSignature ms1, MemberSignature ms2) { int comp = ms1.name.compareTo(ms2.name); if (comp == 0) { comp = ms1.signature.compareTo(ms2.signature); } return comp; } }); for (int i = 0; i < methSigs.length; i++) { MemberSignature sig = methSigs[i]; int mods = sig.member.getModifiers() & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED | Modifier.STATIC | Modifier.FINAL | Modifier.SYNCHRONIZED | Modifier.NATIVE | Modifier.ABSTRACT | Modifier.STRICT); if ((mods & Modifier.PRIVATE) == 0) { dout.writeUTF(sig.name); dout.writeInt(mods); dout.writeUTF(sig.signature.replace('/', '.')); } }
- 【8,9】最后按照JVM规范中描述的一样,计算serialVersionUID的值,这里的算法比较难理解,就不详细解析算法了,有兴趣的读者可通过示例去理解下边这段代码的执行流程以理解该算法,它对应了前一章节JVM规范部分最后那段代码;
MessageDigest md = MessageDigest.getInstance("SHA"); byte[] hashBytes = md.digest(bout.toByteArray()); long hash = 0; for (int i = Math.min(hashBytes.length, 8) - 1; i >= 0; i--) { hash = (hash << 8) | (hashBytes[i] & 0xFF); } return hash;
/** serialPersistentFields value indicating no serializable fields */
public static final ObjectStreamField[] NO_FIELDS =
new ObjectStreamField[0];
private static final ObjectStreamField[] serialPersistentFields =
NO_FIELDS;
getDeclaredSerialFields
private static ObjectStreamField[] getDeclaredSerialFields(Class<?> cl)
throws InvalidClassException
{
ObjectStreamField[] serialPersistentFields = null;
try {
Field f = cl.getDeclaredField("serialPersistentFields");
int mask = Modifier.PRIVATE | Modifier.STATIC | Modifier.FINAL;
if ((f.getModifiers() & mask) == mask) {
f.setAccessible(true);
serialPersistentFields = (ObjectStreamField[]) f.get(null);
}
} catch (Exception ex) {
}
if (serialPersistentFields == null) {
return null;
} else if (serialPersistentFields.length == 0) {
return NO_FIELDS;
}
ObjectStreamField[] boundFields =
new ObjectStreamField[serialPersistentFields.length];
Set<String> fieldNames = new HashSet<>(serialPersistentFields.length);
for (int i = 0; i < serialPersistentFields.length; i++) {
ObjectStreamField spf = serialPersistentFields[i];
String fname = spf.getName();
if (fieldNames.contains(fname)) {
throw new InvalidClassException(
"multiple serializable fields named " + fname);
}
fieldNames.add(fname);
try {
Field f = cl.getDeclaredField(fname);
if ((f.getType() == spf.getType()) &&
((f.getModifiers() & Modifier.STATIC) == 0))
{
boundFields[i] =
new ObjectStreamField(f, spf.isUnshared(), true);
}
} catch (NoSuchFieldException ex) {
}
if (boundFields[i] == null) {
boundFields[i] = new ObjectStreamField(
fname, spf.getType(), spf.isUnshared());
}
}
return boundFields;
}
getDefaultSerialFields
private static ObjectStreamField[] getDefaultSerialFields(Class<?> cl) {
Field[] clFields = cl.getDeclaredFields();
ArrayList<ObjectStreamField> list = new ArrayList<>();
int mask = Modifier.STATIC | Modifier.TRANSIENT;
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]);
}
getSerialFields
private static ObjectStreamField[] getSerialFields(Class<?> cl)
throws InvalidClassException
{
ObjectStreamField[] fields;
if (Serializable.class.isAssignableFrom(cl) &&
!Externalizable.class.isAssignableFrom(cl) &&
!Proxy.isProxyClass(cl) &&
!cl.isInterface())
{
if ((fields = getDeclaredSerialFields(cl)) == null) {
fields = getDefaultSerialFields(cl);
}
Arrays.sort(fields);
} else {
fields = NO_FIELDS;
}
return fields;
}
- 在提取成员属性【字段】的元数据时,会先调用getSerialFields方法从一个类中获取可序列化字段元数据数组信息,这个方法会去调用前两个方法获取成员属性的元数据信息,其判断条件要求这个类满足下边条件:
-- 该类必须实现了Serializable接口;
-- 该类不能实现Externalizable接口;
-- 该类不能是一个Java的动态代理类;
-- 该类不能是一个接口; - 在该类获取元数据的调用过程中,该方法会先调用getDeclaredSerialFields【上述代码中第一个】方法,当调用这个方法返回的值为null,也就是该类中没有定义serialPersistentFields字段的时候,就调用getDefaultSerialFields【上述代码中第二个】方法来获取ObjectStreamField[]数组;
- getDefaultSerialFields的方法就是一步到位,直接使用ArrayList<ObjectStreamField>类型的容器list获取该类中非static和非transitent的字段元数据集合信息,最后将list转化为一个ObjectStreamField[]类型;
- getDeclareSerialFields的方法主要包含两个步骤:先从传入的类中获取serialPersistentFields字段信息,如果serialPersistentFields中定义了重名的成员属性则抛出InvalidClassException异常信息,内部循环中有一个检测重复字段的代码段;随后代码会通过字段名规范化地获取的字段信息,此规范化的过程通过遍历获取的ObjectStreamField[]数组来生成一个新的ObjectStreamField[]类型的数组返回;
new ObjectStreamField(f, spf.isUnshared(), true);
new ObjectStreamField(clFields[i], false, true)
ObjectStreamField[] getFields(boolean copy) {
return copy ? fields.clone() : fields;
}
ObjectStreamField getField(String name, Class<?> type) {
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i];
if (f.getName().equals(name)) {
if (type == null ||
(type == Object.class && !f.isPrimitive()))
{
return f;
}
Class<?> ftype = f.getType();
if (ftype != null && type.isAssignableFrom(ftype)) {
return f;
}
}
}
return null;
}
public ObjectStreamField[] getFields() {
return getFields(true);
}
public ObjectStreamField getField(String name) {
return getField(name, null);
}
上述字段中获取被解析类的字段方法分为两种类型:getFields和getField方法,这两个方法都各自有一个重载方法;
getField——该方法主要用于根据属性名称获取单个成员属性的元数据信息,default域的getField方法中第二个参数告诉JVM是否要创建一个成员属性元数据数组的副本【拷贝】;
上述内部类FieldReflector中包含了四个特殊的方法,这四个方法的详细信息前文介绍过,这里不介绍了,在ObjectStreamClass中同样包含了这四个方法,这四个方法会调用成员fieldRefl【FieldReflector类型】中的四个对应方法,其定义如下:
void getPrimFieldValues(Object obj, byte[] buf) {
fieldRefl.getPrimFieldValues(obj, buf);
}
void setPrimFieldValues(Object obj, byte[] buf) {
fieldRefl.setPrimFieldValues(obj, buf);
}
void getObjFieldValues(Object obj, Object[] vals) {
fieldRefl.getObjFieldValues(obj, vals);
}
void setObjFieldValues(Object obj, Object[] vals) {
fieldRefl.setObjFieldValues(obj, vals);
}
/** class associated with this descriptor (if any) */
private Class<?> cl;
/** name of class represented by this descriptor */
private String name;
/** serialVersionUID of represented class (null if not computed yet) */
private volatile Long suid;
- cl——java.lang.Class<?>
该成员属性主要用于解析类过程中提取类的元数据信息,因为涉及到“反射”的用法,所以该类型对应一个Class<?>类型; - name——java.lang.String
该成员属性表示被解析类的类名信息; - suid——java.lang.Long
该成员属性表示被解析类在序列化过程中的SUID;
/** true if represents dynamic proxy class */
private boolean isProxy;
/** true if represents enum type */
private boolean isEnum;
/** true if represented class implements Serializable */
private boolean serializable;
/** true if represented class implements Externalizable */
private boolean externalizable;
/** true if desc has data written by class-defined writeObject method */
private boolean hasWriteObjectData;
/**
* true if desc has externalizable data written in block data format; this
* must be true by default to accommodate ObjectInputStream subclasses which
* override readClassDescriptor() to return class descriptors obtained from
* ObjectStreamClass.lookup() (see 4461737)
*/
private boolean hasBlockExternalData = true;
- isProxy——boolean
该标记判断当前类是否是一个Java中的动态代理类; - isEnum——boolean
该标记判断当前类是否是一个Java中的Enum枚举类; - serializable——boolean
该标记判断当前类是否实现了Serializable接口; - externalizable——boolean
该标记判断当前类是否实现了Externalizable接口; - hasWriteObjectData——boolean
该标记判断当前类是否重写了writeObject方法,如果写入了则需要标记当前类为SC_WRITE_METHOD类型; - hasBlockExternalData——boolean
该标记和SC_*的五个标记无关,它只是告诉系统当前解析的类会有额外的信息写入到字节流中;
/** exception (if any) thrown while attempting to resolve class */
private ClassNotFoundException resolveEx;
/** exception (if any) to throw if non-enum deserialization attempted */
private ExceptionInfo deserializeEx;
/** exception (if any) to throw if non-enum serialization attempted */
private ExceptionInfo serializeEx;
/** exception (if any) to throw if default serialization attempted */
private ExceptionInfo defaultSerializeEx;
- resolveEx——java.lang.ClassNotFoundException
当ObjectStreamClass解析一个类的元数据时,如果解析的类在类加载器中找不到,则需要抛出该异常信息; - deserializeEx——java.io.ObjectStreamClass.ExceptionInfo
当一个非Enum枚举类型的Java对象被反序列化的时候,若出现异常则将异常信息保存在deserializeEx成员属性中; - serializeEx——java.io.ObjectStreamClass.ExceptionInfo
当一个非Enum枚举类型的Java对象被序列化的时候,若出现异常则将异常信息保存在serializeEx成员属性中; - defaultSerializeEx——java.io.ObjectStreamClass.ExceptionInfo
在执行默认序列化的时候,如果出现了异常信息则异常信息保存在defaultSerializeEx成员属性中;
/** serializable fields */
private ObjectStreamField[] fields;
/** aggregate marshalled size of primitive fields */
private int primDataSize;
/** number of non-primitive fields */
private int numObjFields;
/** reflector for setting/getting serializable field values */
private FieldReflector fieldRefl;
/** data layout of serialized objects described by this class desc */
private volatile ClassDataSlot[] dataLayout;
- fields——java.io.ObjectStreamField[]
当前ObjectStreamClass中包含的所有成员属性的元数据信息,上一个小章节中解析的三个和字段相关的方法其目的就是为了生成当前解析类的字段元数据数组; - primDataSize——int
当前解析类中所有基础类型的成员属性所需要的数据大小; - numObjFields——int
当前解析类中所有非基础类型的成员属性的数量; - fieldRefl——java.io.ObjectStreamClass.FieldReflector
创建一个字段分析器,用于分析被解析类中所有成员属性【字段】的相关元数据信息;
- dataLayout——java.io.ObjectStreamClass.ClassDataSlot[]
创建一个类描述符相关到ClassDataSlot类型的数组;
/** serialization-appropriate constructor, or null if none */
private Constructor cons;
/** class-defined writeObject method, or null if none */
private Method writeObjectMethod;
/** class-defined readObject method, or null if none */
private Method readObjectMethod;
/** class-defined readObjectNoData method, or null if none */
private Method readObjectNoDataMethod;
/** class-defined writeReplace method, or null if none */
private Method writeReplaceMethod;
/** class-defined readResolve method, or null if none */
private Method readResolveMethod;
- cons——java.lang.reflect.Constructor
被解析类的构造函数信息; - writeObjectMethod——java.lang.reflect.Method
被解析类如果重写了writeObject方法则该成员属性是重写过的writeObject方法的元数据信息; - readObjectMethod——java.lang.reflect.Method
被解析类如果重写了readObject方法则该成员属性是重写过的readObject方法的元元数据信息; - readObjectNoDataMethod——java.lang.reflect.Method
被解析类如果重写了readObjectNoData方法则该成员属性是重写过的readObjectNoData方法的元数据信息; - writeReplaceMethod——java.lang.reflect.Method
被解析类如果重写了writeReplace方法则该成员属性是重写过的writeReplace方法的元数据信息; - readResolveMethod——java.lang.reflect.Method
被解析类如果重写了readResolve方法则该成员属性是重写过的readResolve方法的元数据信息;
ObjectStreamClass中还定义了两个成员,该成员表示类被解析类的类描述信息:
/** local class descriptor for represented class (may point to self) */
private ObjectStreamClass localDesc;
/** superclass descriptor appearing in stream */
private ObjectStreamClass superDesc;
- localDesc——java.io.ObjectStreamClass
该类描述信息表示被解析类的元数据信息,它可能直接引用自己【因为当前ObjectStreamClass描述的就是被解析类的元数据信息】; - superDesc——java.io.ObjectStreamClass
该类描述信息表示被解析类的父类元数据信息。
这部分枚举了ObjectStreamClass中所有遵循了Java Bean规范的方法,设置/获取函数:
public String getName() {
return name;
}
public Class<?> forClass() {
return cl;
}
ObjectStreamClass getSuperDesc() {
return superDesc;
}
ObjectStreamClass getLocalDesc() {
return localDesc;
}
boolean isProxy() {
return isProxy;
}
boolean isEnum() {
return isEnum;
}
boolean isExternalizable() {
return externalizable;
}
boolean isSerializable() {
return serializable;
}
boolean hasBlockExternalData() {
return hasBlockExternalData;
}
boolean hasWriteObjectData() {
return hasWriteObjectData;
}
boolean hasWriteObjectMethod() {
return (writeObjectMethod != null);
}
boolean hasReadObjectMethod() {
return (readObjectMethod != null);
}
boolean hasReadObjectNoDataMethod() {
return (readObjectNoDataMethod != null);
}
boolean hasWriteReplaceMethod() {
return (writeReplaceMethod != null);
}
boolean hasReadResolveMethod() {
return (readResolveMethod != null);
}
boolean isInstantiable() {
return (cons != null);
}
int getPrimDataSize() {
return primDataSize;
}
int getNumObjFields() {
return numObjFields;
}
ClassNotFoundException getResolveException() {
return resolveEx;
}
void checkDeserialize() throws InvalidClassException {
if (deserializeEx != null) {
throw deserializeEx.newInvalidClassException();
}
}
void checkSerialize() throws InvalidClassException {
if (serializeEx != null) {
throw serializeEx.newInvalidClassException();
}
}
void checkDefaultSerialize() throws InvalidClassException {
if (defaultSerializeEx != null) {
throw defaultSerializeEx.newInvalidClassException();
}
}
- checkDeserialize
如果被解析的类不支持被反序列化,则该方法会抛出一个InvalidClassException异常信息,但是该方法不针对Enum枚举类型; - checkSerialize
如果被解析的类不支持被序列化,则该方法会抛出一个InvalidClassException异常信息,该方法同样不针对Enum枚举类型; - checkDefaultSerialize
如果被解析的类不支持使用Java中的默认序列化机制,则会抛出一个InvalidClassException异常信息,该方法不针对Enum枚举类型;
构造函数的获取:
getExternalizableConstructor、getSerializableConstructor
private static Constructor getExternalizableConstructor(Class<?> cl) {
try {
Constructor cons = cl.getDeclaredConstructor((Class<?>[]) null);
cons.setAccessible(true);
return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
cons : null;
} catch (NoSuchMethodException ex) {
return null;
}
}
private static Constructor getSerializableConstructor(Class<?> cl) {
Class<?> initCl = cl;
while (Serializable.class.isAssignableFrom(initCl)) {
if ((initCl = initCl.getSuperclass()) == null) {
return null;
}
}
try {
Constructor cons = initCl.getDeclaredConstructor((Class<?>[]) null);
int mods = cons.getModifiers();
if ((mods & Modifier.PRIVATE) != 0 ||
((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
!packageEquals(cl, initCl)))
{
return null;
}
cons = reflFactory.newConstructorForSerialization(cl, cons);
cons.setAccessible(true);
return cons;
} catch (NoSuchMethodException ex) {
return null;
}
}
/** reflection factory for obtaining serialization constructors */
private static final ReflectionFactory reflFactory =
AccessController.doPrivileged(
new ReflectionFactory.GetReflectionFactoryAction());
getInheritableMethod、getPrivateMethod
private static Method getInheritableMethod(Class<?> cl, String name,
Class<?>[] argTypes,
Class<?> returnType)
{
Method meth = null;
Class<?> defCl = cl;
while (defCl != null) {
try {
meth = defCl.getDeclaredMethod(name, argTypes);
break;
} catch (NoSuchMethodException ex) {
defCl = defCl.getSuperclass();
}
}
if ((meth == null) || (meth.getReturnType() != returnType)) {
return null;
}
meth.setAccessible(true);
int mods = meth.getModifiers();
if ((mods & (Modifier.STATIC | Modifier.ABSTRACT)) != 0) {
return null;
} else if ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) != 0) {
return meth;
} else if ((mods & Modifier.PRIVATE) != 0) {
return (cl == defCl) ? meth : null;
} else {
return packageEquals(cl, defCl) ? meth : null;
}
}
private static Method getPrivateMethod(Class<?> cl, String name,
Class<?>[] argTypes,
Class<?> returnType)
{
try {
Method meth = cl.getDeclaredMethod(name, argTypes);
meth.setAccessible(true);
int mods = meth.getModifiers();
return ((meth.getReturnType() == returnType) &&
((mods & Modifier.STATIC) == 0) &&
((mods & Modifier.PRIVATE) != 0)) ? meth : null;
} catch (NoSuchMethodException ex) {
return null;
}
}
- cl——java.lang.Class<?>
该成员函数所属的类; - name——java.lang.String
该成员函数的名称; - argTypes——java.lang.Class<?>[]
该成员函数的参数表; - returnType——java.lang.Class<?>
该成员函数的返回值;
- 函数在执行过程会先去获取成员函数的信息,返回一个Method类型的引用;
- 然后该函数会检查函数的返回值以确认得到的Method引用指向的成员函数是否匹配的;
- 其次该函数会打开访问控制:meth.setAccessible(true);
- 其实上述成员函数的返回部分比较复杂,它分为以下几种情况:
-- 如果该方法是static或abstract修饰的,则返回null;
-- 如果该方法是public和protected修饰的,则返回方法本身;
-- 如果该方法是private的,并且传入cl和defCl表示的类引用相等,则返回该私有方法,否则就返回null;
-- 其他情况则对比该方法所属类的包名是否相同,若相同则返回获取的成员函数,否则返回null;
void invokeWriteObject(Object obj, ObjectOutputStream out)
throws IOException, UnsupportedOperationException
{
if (writeObjectMethod != null) {
try {
writeObjectMethod.invoke(obj, new Object[]{ out });
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof IOException) {
throw (IOException) th;
} else {
throwMiscException(th);
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError();
}
} else {
throw new UnsupportedOperationException();
}
}
- obj——java.lang.Object
该参数表示需要调用writeObject成员函数的对象,即为一个重写了writeObject方法的类对应的实例; - out——java.io.ObjectOutputStream
该参数会作为writeObject成员函数的参数执行传递;
- 如果成员属性writeObjectMethod方法为空,则抛出UnsupportedOperationException异常;
- 如果调用方法过程出现了错误则抛出InvocationTargetException异常,这种情况需要判断是IOException还是其他异常信息,其他异常使用辅助函数throwMiscException处理;
- 如果调用方法是无法通过访问控制的检测则抛出IllegalAccessException异常,这个时候该方法会抛出一个InternalError的错误信息;
void invokeReadObject(Object obj, ObjectInputStream in)
throws ClassNotFoundException, IOException,
UnsupportedOperationException
{
if (readObjectMethod != null) {
try {
readObjectMethod.invoke(obj, new Object[]{ in });
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof ClassNotFoundException) {
throw (ClassNotFoundException) th;
} else if (th instanceof IOException) {
throw (IOException) th;
} else {
throwMiscException(th);
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError();
}
} else {
throw new UnsupportedOperationException();
}
}
void invokeReadObjectNoData(Object obj)
throws IOException, UnsupportedOperationException
{
if (readObjectNoDataMethod != null) {
try {
readObjectNoDataMethod.invoke(obj, (Object[]) null);
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof ObjectStreamException) {
throw (ObjectStreamException) th;
} else {
throwMiscException(th);
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError();
}
} else {
throw new UnsupportedOperationException();
}
}
Object invokeWriteReplace(Object obj)
throws IOException, UnsupportedOperationException
{
if (writeReplaceMethod != null) {
try {
return writeReplaceMethod.invoke(obj, (Object[]) null);
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof ObjectStreamException) {
throw (ObjectStreamException) th;
} else {
throwMiscException(th);
throw new InternalError(); // never reached
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError();
}
} else {
throw new UnsupportedOperationException();
}
}
Object invokeReadResolve(Object obj)
throws IOException, UnsupportedOperationException
{
if (readResolveMethod != null) {
try {
return readResolveMethod.invoke(obj, (Object[]) null);
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof ObjectStreamException) {
throw (ObjectStreamException) th;
} else {
throwMiscException(th);
throw new InternalError(); // never reached
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError();
}
} else {
throw new UnsupportedOperationException();
}
}
- queue——java.lang.ref.ReferenceQueue<Class<?>>
该参数一般会传入一个队列类型的数据结构,Caches中有两个成员是“Queue”类型; - map——java.util.concurrent.ConcurrentMap<? extends java.lang.ref.WeakReference<Class<?>>,?>
该参数表示一个缓存的结构,这个结构和Caches中定义的另外两个缓存成员是一致的;
static void processQueue(ReferenceQueue<Class<?>> queue,
ConcurrentMap<? extends
WeakReference<Class<?>>, ?> map)
{
Reference<? extends Class<?>> ref;
while((ref = queue.poll()) != null) {
map.remove(ref);
}
}
private static void throwMiscException(Throwable th) throws IOException {
if (th instanceof RuntimeException) {
throw (RuntimeException) th;
} else if (th instanceof Error) {
throw (Error) th;
} else {
IOException ex = new IOException("unexpected exception type");
ex.initCause(th);
throw ex;
}
}
private static boolean classNamesEqual(String name1, String name2) {
name1 = name1.substring(name1.lastIndexOf('.') + 1);
name2 = name2.substring(name2.lastIndexOf('.') + 1);
return name1.equals(name2);
}
private static boolean packageEquals(Class<?> cl1, Class<?> cl2) {
return (cl1.getClassLoader() == cl2.getClassLoader() &&
getPackageName(cl1).equals(getPackageName(cl2)));
}
private static String getPackageName(Class<?> cl) {
String s = cl.getName();
int i = s.lastIndexOf('[');
if (i >= 0) {
s = s.substring(i + 2);
}
i = s.lastIndexOf('.');
return (i >= 0) ? s.substring(0, i) : "";
}
private void computeFieldOffsets() throws InvalidClassException {
primDataSize = 0;
numObjFields = 0;
int firstObjIndex = -1;
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i];
switch (f.getTypeCode()) {
case 'Z':
case 'B':
f.setOffset(primDataSize++);
break;
case 'C':
case 'S':
f.setOffset(primDataSize);
primDataSize += 2;
break;
case 'I':
case 'F':
f.setOffset(primDataSize);
primDataSize += 4;
break;
case 'J':
case 'D':
f.setOffset(primDataSize);
primDataSize += 8;
break;
case '[':
case 'L':
f.setOffset(numObjFields++);
if (firstObjIndex == -1) {
firstObjIndex = i;
}
break;
default:
throw new InternalError();
}
}
if (firstObjIndex != -1 &&
firstObjIndex + numObjFields != fields.length)
{
throw new InvalidClassException(name, "illegal field order");
}
}
- boolean【Z】、byte【B】
——占用1个字节,primDataSize每次增加1,numObjFields不变; - char【C】、short【S】
——占用2个字节,primDataSize每次增加2,numObjFields不变; - int【I】、float【F】
——占用4个字节,primDataSize每次增加4,numObjFields不变; - long【J】、double【D】
——占用8个字节,primDataSize每次增加8,numObjFields不变; - 数组array【[】、对象object【L】
——primDataSize不变,numObjFields每次增加1
public String toString() {
return name + ": static final long serialVersionUID = " +
getSerialVersionUID() + "L;";
}
private ObjectStreamClass getVariantFor(Class<?> cl)
throws InvalidClassException
{
if (this.cl == cl) {
return this;
}
ObjectStreamClass desc = new ObjectStreamClass();
if (isProxy) {
desc.initProxy(cl, null, superDesc);
} else {
desc.initNonProxy(this, cl, null, superDesc);
}
return desc;
}
private static FieldReflector getReflector(ObjectStreamField[] fields,
ObjectStreamClass localDesc)
throws InvalidClassException
{
// class irrelevant if no fields
Class<?> cl = (localDesc != null && fields.length > 0) ?
localDesc.cl : null;
processQueue(Caches.reflectorsQueue, Caches.reflectors);
FieldReflectorKey key = new FieldReflectorKey(cl, fields,
Caches.reflectorsQueue);
Reference<?> ref = Caches.reflectors.get(key);
Object entry = null;
if (ref != null) {
entry = ref.get();
}
EntryFuture future = null;
if (entry == null) {
EntryFuture newEntry = new EntryFuture();
Reference<?> newRef = new SoftReference<>(newEntry);
do {
if (ref != null) {
Caches.reflectors.remove(key, ref);
}
ref = Caches.reflectors.putIfAbsent(key, newRef);
if (ref != null) {
entry = ref.get();
}
} while (ref != null && entry == null);
if (entry == null) {
future = newEntry;
}
}
if (entry instanceof FieldReflector) { // check common case first
return (FieldReflector) entry;
} else if (entry instanceof EntryFuture) {
entry = ((EntryFuture) entry).get();
} else if (entry == null) {
try {
entry = new FieldReflector(matchFields(fields, localDesc));
} catch (Throwable th) {
entry = th;
}
future.set(entry);
Caches.reflectors.put(key, new SoftReference<Object>(entry));
}
if (entry instanceof FieldReflector) {
return (FieldReflector) entry;
} else if (entry instanceof InvalidClassException) {
throw (InvalidClassException) entry;
} else if (entry instanceof RuntimeException) {
throw (RuntimeException) entry;
} else if (entry instanceof Error) {
throw (Error) entry;
} else {
throw new InternalError("unexpected entry: " + entry);
}
}
private static ObjectStreamField[] matchFields(ObjectStreamField[] fields,
ObjectStreamClass localDesc)
throws InvalidClassException
{
ObjectStreamField[] localFields = (localDesc != null) ?
localDesc.fields : NO_FIELDS;
/*
* Even if fields == localFields, we cannot simply return localFields
* here. In previous implementations of serialization,
* ObjectStreamField.getType() returned Object.class if the
* ObjectStreamField represented a non-primitive field and belonged to
* a non-local class descriptor. To preserve this (questionable)
* behavior, the ObjectStreamField instances returned by matchFields
* cannot report non-primitive types other than Object.class; hence
* localFields cannot be returned directly.
*/
ObjectStreamField[] matches = new ObjectStreamField[fields.length];
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i], m = null;
for (int j = 0; j < localFields.length; j++) {
ObjectStreamField lf = localFields[j];
if (f.getName().equals(lf.getName())) {
if ((f.isPrimitive() || lf.isPrimitive()) &&
f.getTypeCode() != lf.getTypeCode())
{
throw new InvalidClassException(localDesc.name,
"incompatible types for field " + f.getName());
}
if (lf.getField() != null) {
m = new ObjectStreamField(
lf.getField(), lf.isUnshared(), false);
} else {
m = new ObjectStreamField(
lf.getName(), lf.getSignature(), lf.isUnshared());
}
}
}
if (m == null) {
m = new ObjectStreamField(
f.getName(), f.getSignature(), false);
}
m.setOffset(f.getOffset());
matches[i] = m;
}
return matches;
}
- 如果被解析的类是实现了Externalizable接口可外部化的一个类,则调用它的public无参构造函数;
- 如果被解析的类是实现了Serializable接口可序列化的一个类,则调用先调用它的父类的无参构造函数直到当前类实现递归调用;
- 如果当前的类对应元数据信息和关联类不匹配则抛出UnsupportedOperationException异常;
- 如果被解析的类不具有“可序列化”的语义,或者它的无参构造函数不能调用,则同样抛出UnsupportedOperationException异常;
Object newInstance()
throws InstantiationException, InvocationTargetException,
UnsupportedOperationException
{
if (cons != null) {
try {
return cons.newInstance();
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError();
}
} else {
throw new UnsupportedOperationException();
}
}
ClassDataSlot[] getClassDataLayout() throws InvalidClassException {
// REMIND: synchronize instead of relying on volatile?
if (dataLayout == null) {
dataLayout = getClassDataLayout0();
}
return dataLayout;
}
private ClassDataSlot[] getClassDataLayout0()
throws InvalidClassException
{
ArrayList<ClassDataSlot> slots = new ArrayList<>();
Class<?> start = cl, end = cl;
// locate closest non-serializable superclass
while (end != null && Serializable.class.isAssignableFrom(end)) {
end = end.getSuperclass();
}
for (ObjectStreamClass d = this; d != null; d = d.superDesc) {
// search up inheritance hierarchy for class with matching name
String searchName = (d.cl != null) ? d.cl.getName() : d.name;
Class<?> match = null;
for (Class<?> c = start; c != end; c = c.getSuperclass()) {
if (searchName.equals(c.getName())) {
match = c;
break;
}
}
// add "no data" slot for each unmatched class below match
if (match != null) {
for (Class<?> c = start; c != match; c = c.getSuperclass()) {
slots.add(new ClassDataSlot(
ObjectStreamClass.lookup(c, true), false));
}
start = match.getSuperclass();
}
// record descriptor/class pairing
slots.add(new ClassDataSlot(d.getVariantFor(match), true));
}
// add "no data" slot for any leftover unmatched classes
for (Class<?> c = start; c != end; c = c.getSuperclass()) {
slots.add(new ClassDataSlot(
ObjectStreamClass.lookup(c, true), false));
}
// order slots from superclass -> subclass
Collections.reverse(slots);
return slots.toArray(new ClassDataSlot[slots.size()]);
}
lookup、lookupAny
public static ObjectStreamClass lookup(Class<?> cl) {
return lookup(cl, false);
}
public static ObjectStreamClass lookupAny(Class<?> cl) {
return lookup(cl, true);
}
static ObjectStreamClass lookup(Class<?> cl, boolean all) {
if (!(all || Serializable.class.isAssignableFrom(cl))) {
return null;
}
processQueue(Caches.localDescsQueue, Caches.localDescs);
WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
Reference<?> ref = Caches.localDescs.get(key);
Object entry = null;
if (ref != null) {
entry = ref.get();
}
EntryFuture future = null;
if (entry == null) {
EntryFuture newEntry = new EntryFuture();
Reference<?> newRef = new SoftReference<>(newEntry);
do {
if (ref != null) {
Caches.localDescs.remove(key, ref);
}
ref = Caches.localDescs.putIfAbsent(key, newRef);
if (ref != null) {
entry = ref.get();
}
} while (ref != null && entry == null);
if (entry == null) {
future = newEntry;
}
}
if (entry instanceof ObjectStreamClass) { // check common case first
return (ObjectStreamClass) entry;
}
if (entry instanceof EntryFuture) {
future = (EntryFuture) entry;
if (future.getOwner() == Thread.currentThread()) {
/*
* Handle nested call situation described by 4803747: waiting
* for future value to be set by a lookup() call further up the
* stack will result in deadlock, so calculate and set the
* future value here instead.
*/
entry = null;
} else {
entry = future.get();
}
}
if (entry == null) {
try {
entry = new ObjectStreamClass(cl);
} catch (Throwable th) {
entry = th;
}
if (future.set(entry)) {
Caches.localDescs.put(key, new SoftReference<Object>(entry));
} else {
// nested lookup call already set future
entry = future.get();
}
}
if (entry instanceof ObjectStreamClass) {
return (ObjectStreamClass) entry;
} else if (entry instanceof RuntimeException) {
throw (RuntimeException) entry;
} else if (entry instanceof Error) {
throw (Error) entry;
} else {
throw new InternalError("unexpected entry: " + entry);
}
}
- 先检查传入的类是否支持序列化,第二个参数告诉ObjectStreamClass实例是否需要检测传入类的可序列化语义,lookup对外的API方法调用时传入的第二个参数为false,lookupAny对外的API方法调用时传入的第二个参数为true——实际上第二个参数若为false就必须检查被解析类是否具有“可序列化”的语义【这里的可序列化语义仅仅检查传入类是否实现了Serializable接口】;
if (!(all || Serializable.class.isAssignableFrom(cl))) { return null; }
- 使用processQueue方法清空Caches类中的缓存哈希表localDescs,其缓存清除的哈希表键值是保存于一个ReferenceQueue队列localDescsQueue中,清除这个Caches类中的缓存哈希表时,需要根据ReferenceQueue中保存的键值来清除缓存中的项,从这一点可以知道Caches类中的四个成员是成对使用的,一对用于分析类,另外一对用于分析成员属性;
processQueue(Caches.localDescsQueue, Caches.localDescs);
- 通过传入的cl参数以及Caches中的localDescsQueue属性构造一个新的WeakClassKey对象key,这个引用key会在后边作为缓存哈希表的键值;
WeakClassKey key = new WeakClassKey(cl, Caches.localDescsQueue);
- 利用上一步创建的WeakClassKey对象作为哈希表键值,尝试先从缓存Caches.localDescs的哈希表中获取一个存在的引用ref;
Reference<?> ref = Caches.localDescs.get(key);
- 创建一个新的Object引用entry,赋值为null;若第四步获取的ref引用不为空,则直接将ref指向的对象【缓存中】赋给entry;
Object entry = null; if (ref != null) { entry = ref.get(); }
- 创建一个新的EntryFuture引用future,如果entry为null的时候则配合Caches中的缓存localDescs初始化entry;
EntryFuture future = null; if (entry == null) { EntryFuture newEntry = new EntryFuture(); Reference<?> newRef = new SoftReference<>(newEntry); do { if (ref != null) { Caches.localDescs.remove(key, ref); } ref = Caches.localDescs.putIfAbsent(key, newRef); if (ref != null) { entry = ref.get(); } } while (ref != null && entry == null); if (entry == null) { future = newEntry; } }
- 如果从缓存中拿到的entry类型本身就是ObjectStreamClass则直接返回这个entry;
if (entry instanceof ObjectStreamClass) { // check common case first return (ObjectStreamClass) entry; }
- 如果从缓存中拿到的entry类型为EntryFuture,则从EntryFuture中去获取entry;
if (entry instanceof EntryFuture) { future = (EntryFuture) entry; if (future.getOwner() == Thread.currentThread()) { /* * Handle nested call situation described by 4803747: waiting * for future value to be set by a lookup() call further up the * stack will result in deadlock, so calculate and set the * future value here instead. */ entry = null; } else { entry = future.get(); } }
- 到目前为止拿到的entry还是一个null的时候就直接使用当前的cl参数构造一个新的ObjectStreamClass,构造完成过后将entry放入localDescs缓存中;
if (entry == null) { try { entry = new ObjectStreamClass(cl); } catch (Throwable th) { entry = th; } if (future.set(entry)) { Caches.localDescs.put(key, new SoftReference<Object>(entry)); } else { // nested lookup call already set future entry = future.get(); } }
- 最终判断entry的类型执行异常处理或者返回;
if (entry instanceof ObjectStreamClass) { return (ObjectStreamClass) entry; } else if (entry instanceof RuntimeException) { throw (RuntimeException) entry; } else if (entry instanceof Error) { throw (Error) entry; } else { throw new InternalError("unexpected entry: " + entry); }
private ObjectStreamClass(final Class<?> cl) {
this.cl = cl;
name = cl.getName();
isProxy = Proxy.isProxyClass(cl);
isEnum = Enum.class.isAssignableFrom(cl);
serializable = Serializable.class.isAssignableFrom(cl);
externalizable = Externalizable.class.isAssignableFrom(cl);
Class<?> superCl = cl.getSuperclass();
superDesc = (superCl != null) ? lookup(superCl, false) : null;
localDesc = this;
if (serializable) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
if (isEnum) {
suid = Long.valueOf(0);
fields = NO_FIELDS;
return null;
}
if (cl.isArray()) {
fields = NO_FIELDS;
return null;
}
suid = getDeclaredSUID(cl);
try {
fields = getSerialFields(cl);
computeFieldOffsets();
} catch (InvalidClassException e) {
serializeEx = deserializeEx =
new ExceptionInfo(e.classname, e.getMessage());
fields = NO_FIELDS;
}
if (externalizable) {
cons = getExternalizableConstructor(cl);
} else {
cons = getSerializableConstructor(cl);
writeObjectMethod = getPrivateMethod(cl, "writeObject",
new Class<?>[] { ObjectOutputStream.class },
Void.TYPE);
readObjectMethod = getPrivateMethod(cl, "readObject",
new Class<?>[] { ObjectInputStream.class },
Void.TYPE);
readObjectNoDataMethod = getPrivateMethod(
cl, "readObjectNoData", null, Void.TYPE);
hasWriteObjectData = (writeObjectMethod != null);
}
writeReplaceMethod = getInheritableMethod(
cl, "writeReplace", null, Object.class);
readResolveMethod = getInheritableMethod(
cl, "readResolve", null, Object.class);
return null;
}
});
} else {
suid = Long.valueOf(0);
fields = NO_FIELDS;
}
try {
fieldRefl = getReflector(fields, this);
} catch (InvalidClassException ex) {
// field mismatches impossible when matching local fields vs. self
throw new InternalError();
}
if (deserializeEx == null) {
if (isEnum) {
deserializeEx = new ExceptionInfo(name, "enum type");
} else if (cons == null) {
deserializeEx = new ExceptionInfo(name, "no valid constructor");
}
}
for (int i = 0; i < fields.length; i++) {
if (fields[i].getField() == null) {
defaultSerializeEx = new ExceptionInfo(
name, "unmatched serializable field(s) declared");
}
}
}
ObjectStreamClass() {
}
- 设置成员属性的基本信息,传入的是一个Class<?>类型的参数cl,可以通过Java反射获得基本成员属性的信息:
cl——直接将该引用指向传入的类;
name——获取传入类的类名;
isProxy——调用java.lang.reflect.Proxy的isProxyClass方法判断传入类是否是一个Java中的动态代理类;
isEnum——判断当前类是否是一个Enum枚举的类;
serializable——判断当前类是否实现了Serializable接口;
externalizable——判断当前类是否实现了Externalizable接口; - 设置localDesc和superDesc两个成员属性:
superDesc——通过getSuperclass方法获取当前类的父类,然后通过lookup方法获取父类的元数据信息,生成一个ObjectStreamClass实例,第二个参数为false表示要求检测父类是否实现了Serializable接口的;
localDesc——直接将当前ObjectStreamClass引用this赋值给localDesc引用; - 然后需要判断当前解析类是否支持可序列化【实现Serializable接口】,这个时候不需要通过Serializable类来判断被解析类的“可序列化”的语义,直接检查成员属性serializable即可——注意这里会有一个包含关系,如果一个类是实现了Externalizable接口的,那么这个类一定实现了Serializable接口的,前文提到过Serializable接口是Externalizable的父接口;
如果当前解析类没有实现Serializable接口,则设置成员属性suid和fields的值:
suid——0L;
fields——NO_FIELDS; - 如果当前解析类实现了Serializable接口,代码会先调用Java语言中的访问控制器来判断代码是否拥有执行权限;
- 通过Java的访问控制器过后,则同样需要设置可序列化的情况下成员属性suid和fields的值,先看看设置这两个成员属性设置的过程:
从上述代码可以看到,这段代码的设置如下:if (isEnum) { suid = Long.valueOf(0); fields = NO_FIELDS; return null; } if (cl.isArray()) { fields = NO_FIELDS; return null; } suid = getDeclaredSUID(cl); try { fields = getSerialFields(cl); computeFieldOffsets(); } catch (InvalidClassException e) { serializeEx = deserializeEx = new ExceptionInfo(e.classname, e.getMessage()); fields = NO_FIELDS; }
如果被解析类是枚举类型——suid的值为0L,fields的值为NO_FIELDS;
如果被解析类是数组类型——fields的值为NO_FIELDS,suid的值会继续运算;
suid的值的计算——getDeclaredSUID方法运算,前文分析过getDeclaredSUID方法的代码细节,这里不重复;
fields的值的计算——getSerialFields方法运算,前文分析过getSerialFields方法的代码细节,这里不重复;
*:这个地方有个小细节,在代码中调用了computeFieldOffsets方法,这个方法调用过后,两个成员属性primDataSize和numObjFields的值也就有了【不针对枚举类型和数组类型】; - 在设置了suid和fields两个成员属性的值过后,则需要设置下边几个成员属性:
cons、writeObjectMethod、readObjectMethod、readObjectNoDataMethod、hasWriteObjectData、writeReplaceMethod、readResolveMethod;
相信不需要解释上边代码的含义了。代码执行到这里,大部分成员属性的构造初始化过程都完成了;if (externalizable) { cons = getExternalizableConstructor(cl); } else { cons = getSerializableConstructor(cl); writeObjectMethod = getPrivateMethod(cl, "writeObject", new Class<?>[] { ObjectOutputStream.class }, Void.TYPE); readObjectMethod = getPrivateMethod(cl, "readObject", new Class<?>[] { ObjectInputStream.class }, Void.TYPE); readObjectNoDataMethod = getPrivateMethod( cl, "readObjectNoData", null, Void.TYPE); hasWriteObjectData = (writeObjectMethod != null); } writeReplaceMethod = getInheritableMethod( cl, "writeReplace", null, Object.class); readResolveMethod = getInheritableMethod( cl, "readResolve", null, Object.class); return null;
- 接下来就初始化fields以及fieldRefl两个成员属性,通过调用getReflector方法来计算这两个属性的值,回顾一下上边的getReflector方法传入的参数fields是传的引用,所以在执行getReflector方法后传入的fields的值就被初始化了,而且该方法的返回对象的引用会传给fieldRefl——getReflector方法执行过后具有“二义性”,它不是单纯地返回了一个FieldReflector,在执行过程中还修改了fields引用的对象的值;
- 最后看看剩余的几个和异常信息相关的成员属性的初始化:
前文中虽然讲过几个异常信息类,这里先看看第5步解析的代码中的catch块的内容:if (deserializeEx == null) { if (isEnum) { deserializeEx = new ExceptionInfo(name, "enum type"); } else if (cons == null) { deserializeEx = new ExceptionInfo(name, "no valid constructor"); } } for (int i = 0; i < fields.length; i++) { if (fields[i].getField() == null) { defaultSerializeEx = new ExceptionInfo( name, "unmatched serializable field(s) declared"); } }
从上边这段代码中可以看到serializeEx和deserializeEx会在获取被解析类的可序列化字段元数据过程中因为出现异常而设置;其实isEnum为空的语句是一句“防御式”的编程,在前边调用过程如果isEnum判断为真则serializeEx和deserializeEx都会为null,而这里再作判断的情况可能就属于十分稀有的情况了;serializeEx = deserializeEx = new ExceptionInfo(e.classname, e.getMessage()); fields = NO_FIELDS;
到这里ObjectStreamClass中就只剩下4个成员函数没有解析了:initProxy、initNonProxy、readNonProxy、writeNonProxy,这四个方法属于ObjectStreamClass中的核心方法,所以这四个方法会在接下来重点解析。本章节先看看初始化解析方法——initProxy和initNonProxy成员函数,initProxy负责解析动态代理类,initNonProxy负责解析非动态代理类,这两个方法会用于初始化当前ObjectStreamClass元数据实例。
initProxy成员函数:
void initProxy(Class<?> cl,
ClassNotFoundException resolveEx,
ObjectStreamClass superDesc)
throws InvalidClassException
{
this.cl = cl;
this.resolveEx = resolveEx;
this.superDesc = superDesc;
isProxy = true;
serializable = true;
suid = Long.valueOf(0);
fields = NO_FIELDS;
if (cl != null) {
localDesc = lookup(cl, true);
if (!localDesc.isProxy) {
throw new InvalidClassException(
"cannot bind proxy descriptor to a non-proxy class");
}
name = localDesc.name;
externalizable = localDesc.externalizable;
cons = localDesc.cons;
writeReplaceMethod = localDesc.writeReplaceMethod;
readResolveMethod = localDesc.readResolveMethod;
deserializeEx = localDesc.deserializeEx;
}
fieldRefl = getReflector(fields, localDesc);
}
- cl——java.lang.Class<?>
该参数表示需要被解析类,该方法解析的元数据信息就是从这个类中提取的; - resolveEx——java.lang.ClassNotFoundException
该参数用于处理启用”resolve”功能时的异常信息; - superDesc——java.io.ObjectStreamClass
该参数表示当前类对应的父类的元数据信息;
- 看看设置成员函数的过程:
cl——将传入的Class<?>类型的参数赋给成员属性cl;
resolveEx——将传入的ClassNotFoundException类型的参数赋给成员属性resolveExt;
superDesc——将传入的ObjectStreamClass类型的参数赋给成员属性superDesc;
isProxy——因为这个成员函数的作用就是解析动态代理类,所以isProxy设置为true;
serializable——标识当前解析类是可序列化的,设置值为true;
suid——因为解析类是动态代理类,所以suid为0L;
fields——同上述理由,设置fields的值为NO_FIELDS; - 如果成员函数cl不为null,则执行额外逻辑:
localDesc——调用lookup方法解析传入类,获取该类的元数据信息,并将该元数据引用赋给localDesc,localDesc赋值过后,判断解析类是否为一个动态代理类,如果不是动态代理类则抛出InvalidClassException异常;
下边的几个成员属性直接从localDesc中读取:
name、externalizable、cons、writeReplaceMethod、readResolveMethod、deserializable - 最后设置成员属性fieldRefls,直接调用getReflector方法获得;
void initNonProxy(ObjectStreamClass model,
Class<?> cl,
ClassNotFoundException resolveEx,
ObjectStreamClass superDesc)
throws InvalidClassException
{
this.cl = cl;
this.resolveEx = resolveEx;
this.superDesc = superDesc;
name = model.name;
suid = Long.valueOf(model.getSerialVersionUID());
isProxy = false;
isEnum = model.isEnum;
serializable = model.serializable;
externalizable = model.externalizable;
hasBlockExternalData = model.hasBlockExternalData;
hasWriteObjectData = model.hasWriteObjectData;
fields = model.fields;
primDataSize = model.primDataSize;
numObjFields = model.numObjFields;
if (cl != null) {
localDesc = lookup(cl, true);
if (localDesc.isProxy) {
throw new InvalidClassException(
"cannot bind non-proxy descriptor to a proxy class");
}
if (isEnum != localDesc.isEnum) {
throw new InvalidClassException(isEnum ?
"cannot bind enum descriptor to a non-enum class" :
"cannot bind non-enum descriptor to an enum class");
}
if (serializable == localDesc.serializable &&
!cl.isArray() &&
suid.longValue() != localDesc.getSerialVersionUID())
{
throw new InvalidClassException(localDesc.name,
"local class incompatible: " +
"stream classdesc serialVersionUID = " + suid +
", local class serialVersionUID = " +
localDesc.getSerialVersionUID());
}
if (!classNamesEqual(name, localDesc.name)) {
throw new InvalidClassException(localDesc.name,
"local class name incompatible with stream class " +
"name \"" + name + "\"");
}
if (!isEnum) {
if ((serializable == localDesc.serializable) &&
(externalizable != localDesc.externalizable))
{
throw new InvalidClassException(localDesc.name,
"Serializable incompatible with Externalizable");
}
if ((serializable != localDesc.serializable) ||
(externalizable != localDesc.externalizable) ||
!(serializable || externalizable))
{
deserializeEx = new ExceptionInfo(
localDesc.name, "class invalid for deserialization");
}
}
cons = localDesc.cons;
writeObjectMethod = localDesc.writeObjectMethod;
readObjectMethod = localDesc.readObjectMethod;
readObjectNoDataMethod = localDesc.readObjectNoDataMethod;
writeReplaceMethod = localDesc.writeReplaceMethod;
readResolveMethod = localDesc.readResolveMethod;
if (deserializeEx == null) {
deserializeEx = localDesc.deserializeEx;
}
}
fieldRefl = getReflector(fields, localDesc);
// reassign to matched fields so as to reflect local unshared settings
fields = fieldRefl.getFields();
}
- model——java.io.ObjectStreamClass
该参数表示需要传入的元数据信息,调用该成员函数的时候会利用传入的元数据信息为当前实例赋值;
- 成员属性cl、resolveEx、superDesc和initProxy使用相同的方式赋值;
- 成员属性name、isEnum、serializable、externalizable、hasBlockExternalData、hasWriteObjectData、fields、primDataSize、numObjects直接从传入参数model中取得;
- 成员属性suid和isProxy的设置稍有不同,suid通过调用model的getSerialVersionUID方法获得,isProxy直接设置成false——因为initNonProxy成员函数的目的是解析非动态代理类,所以直接为isProxy赋值;
- 当成员cl不为null时,initNonProxy的执行流程和initProxy差不多,唯一不同的是多了许多异常信息,看看抛出异常的情况:
——如果被解析类为动态代理类则抛出异常;
——如果model中的isEnum【第二步已经赋值给isEnum了】和localDesc中的isEnum不相等则抛出异常;
——如果model中的serializable和localDesc中的serializable相等、并且cl不是数组、并且model中suid的值和localDesc中suid的值不相等时,则抛出异常【前边三个条件同时满足才行】;
——如果model中的name和localDesc中的name不相等时则抛出异常;
——如果被解析类不是枚举类型时抛异常的情况分为下边两种:
(1) 如果model中serializable和localDesc中的serializable相等,但externalizable不相等则抛出异常;
(2) 如果model和localDesc描述的类任何一个类没有序列化语义则抛出异常【未实现Serializable或者Externalizable接口】; - fieldRefl成员属性的赋值和initProxy一样;
- initNonProxy成员属性多了下边这行代码,至于目的可见注释部分内容:
// reassign to matched fields so as to reflect local unshared settings fields = fieldRefl.getFields();
writeNonProxy序列化函数:
void writeNonProxy(ObjectOutputStream out) throws IOException {
out.writeUTF(name);
out.writeLong(getSerialVersionUID());
byte flags = 0;
if (externalizable) {
flags |= ObjectStreamConstants.SC_EXTERNALIZABLE;
int protocol = out.getProtocolVersion();
if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) {
flags |= ObjectStreamConstants.SC_BLOCK_DATA;
}
} else if (serializable) {
flags |= ObjectStreamConstants.SC_SERIALIZABLE;
}
if (hasWriteObjectData) {
flags |= ObjectStreamConstants.SC_WRITE_METHOD;
}
if (isEnum) {
flags |= ObjectStreamConstants.SC_ENUM;
}
out.writeByte(flags);
out.writeShort(fields.length);
for (int i = 0; i < fields.length; i++) {
ObjectStreamField f = fields[i];
out.writeByte(f.getTypeCode());
out.writeUTF(f.getName());
if (!f.isPrimitive()) {
out.writeTypeString(f.getTypeString());
}
}
}
- 先调用writeUTF方法写入类名到字节流,这里的类名为带了包名的类全名:
out.writeUTF(name);
- 然后调用writeLong方法写入suid的值到字节流,也就是前边解析二进制序列时serialVersionUID的值;
out.writeLong(getSerialVersionUID());
- 写入标记到字节流,这里的标记为前文提到的五个SC_*标记,注意这个标记只占一个字节的数据,flags的类型为byte,至于标记的运算细节很简单,读者可仔细阅读下边的代码:
byte flags = 0; if (externalizable) { flags |= ObjectStreamConstants.SC_EXTERNALIZABLE; int protocol = out.getProtocolVersion(); if (protocol != ObjectStreamConstants.PROTOCOL_VERSION_1) { flags |= ObjectStreamConstants.SC_BLOCK_DATA; } } else if (serializable) { flags |= ObjectStreamConstants.SC_SERIALIZABLE; } if (hasWriteObjectData) { flags |= ObjectStreamConstants.SC_WRITE_METHOD; } if (isEnum) { flags |= ObjectStreamConstants.SC_ENUM; } out.writeByte(flags);
- 写入当前类中成员属性的数量信息到字节流:
out.writeShort(fields.length);
- 最后写入每一个字段的信息,字段信息包含三部分内容:类型代码、字段名、字段类型字符串【该信息不适用于基础类型的数据】
for (int i = 0; i < fields.length; i++) { ObjectStreamField f = fields[i]; out.writeByte(f.getTypeCode()); out.writeUTF(f.getName()); if (!f.isPrimitive()) { out.writeTypeString(f.getTypeString()); } }
void readNonProxy(ObjectInputStream in)
throws IOException, ClassNotFoundException
{
name = in.readUTF();
suid = Long.valueOf(in.readLong());
isProxy = false;
byte flags = in.readByte();
hasWriteObjectData =
((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0);
hasBlockExternalData =
((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0);
externalizable =
((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0);
boolean sflag =
((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0);
if (externalizable && sflag) {
throw new InvalidClassException(
name, "serializable and externalizable flags conflict");
}
serializable = externalizable || sflag;
isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0);
if (isEnum && suid.longValue() != 0L) {
throw new InvalidClassException(name,
"enum descriptor has non-zero serialVersionUID: " + suid);
}
int numFields = in.readShort();
if (isEnum && numFields != 0) {
throw new InvalidClassException(name,
"enum descriptor has non-zero field count: " + numFields);
}
fields = (numFields > 0) ?
new ObjectStreamField[numFields] : NO_FIELDS;
for (int i = 0; i < numFields; i++) {
char tcode = (char) in.readByte();
String fname = in.readUTF();
String signature = ((tcode == 'L') || (tcode == '[')) ?
in.readTypeString() : new String(new char[] { tcode });
try {
fields[i] = new ObjectStreamField(fname, signature, false);
} catch (RuntimeException e) {
throw (IOException) new InvalidClassException(name,
"invalid descriptor for field " + fname).initCause(e);
}
}
computeFieldOffsets();
}
- 先从字节流中读取类名信息:
name = in.readUTF();
- 其次从字节流中读取suid的信息,即类的serialVersionUID信息:
suid = Long.valueOf(in.readLong());
- 从字节流中读取SC_*标记信息,通过该标记信息设置对应的成员属性:
byte flags = in.readByte(); hasWriteObjectData = ((flags & ObjectStreamConstants.SC_WRITE_METHOD) != 0); hasBlockExternalData = ((flags & ObjectStreamConstants.SC_BLOCK_DATA) != 0); externalizable = ((flags & ObjectStreamConstants.SC_EXTERNALIZABLE) != 0); boolean sflag = ((flags & ObjectStreamConstants.SC_SERIALIZABLE) != 0); if (externalizable && sflag) { throw new InvalidClassException( name, "serializable and externalizable flags conflict"); } serializable = externalizable || sflag; isEnum = ((flags & ObjectStreamConstants.SC_ENUM) != 0); if (isEnum && suid.longValue() != 0L) { throw new InvalidClassException(name, "enum descriptor has non-zero serialVersionUID: " + suid); }
- 从字节流中读取成员属性的数量信息:
int numFields = in.readShort(); if (isEnum && numFields != 0) { throw new InvalidClassException(name, "enum descriptor has non-zero field count: " + numFields); }
- 最后从字节流中读取每一个字段的信息,字段信息包括:类型代码、字段名、字段类型字符串【非基础类型数据】:
fields = (numFields > 0) ? new ObjectStreamField[numFields] : NO_FIELDS; for (int i = 0; i < numFields; i++) { char tcode = (char) in.readByte(); String fname = in.readUTF(); String signature = ((tcode == 'L') || (tcode == '[')) ? in.readTypeString() : new String(new char[] { tcode }); try { fields[i] = new ObjectStreamField(fname, signature, false); } catch (RuntimeException e) { throw (IOException) new InvalidClassException(name, "invalid descriptor for field " + fname).initCause(e); } }
- 签名信息
——包括:成员属性签名、成员函数签名、构造函数签名,结合代码中的signature去理解;
- 关于类型
——区分:类型、类型代码、类型字符串的概念; - 五个SC标记
——SC_WRITE_METHOD、SC_BLOCKDATA、SC_SERIALIZABLE、SC_EXTERNALIZABLE、SC_ENUM,这五个标记的概念在源代码中多次涉及到; - 缓存
——理解ObjectStreamClass中的Caches类,通过本文的截图理解缓存的数据结构; - 两种Key:WeakClassKey & FieldReflectorKey
——理解两个内部类WeakClassKey和FieldRefectorKey的用法,这两个Key一般作为哈希表缓存的键值使用; - ClassDataSlot
——理解ClassDataSlot在源代码中的概念; - SUID
——结合前文JVM的序列化规范中提及的SUID理解源代码中针对SUID的计算方法; - FieldReflector
——理解源代码中内部类FieldReflector的用法,看看它是如何去分析类中的各个字段的; - serialPersistentFields
——这是一个Java类处理可序列化成员属性的另外一种方式,理解ObjectStreamClass中如何处理该字段; - 字段数组
——源代码中多次获取了ObjectStreamField[]的字段元数据数组,理解源代码中和这点相关的所有方法; - 特殊方法
——可序列化的类中包含了五个特殊方法,看看这五个特殊方法在源代码中如何处理:writeObject、readObject、readObjectNoData、writeReplace、readResolve; - 异常管理
——管理系统中的所有异常信息,理解如何在源代码中处理异常信息; - lookup
——理解ObjectStreamClass中的lookup方法,对比这两个方法和构造函数如何设置成员属性的相关信息; - Java语言基础
——若要理解上述源代码需要准备的Java知识:反射、动态代理类、安全检测、数据类型、基础算法等;