当前位置:编程学习 > JAVA >>

java对序列化serialVersionUID的处理分析

继上次分析了java的序列化过程之后,对于serialVersionUID的处理还不是很清晰,今天再看下代码,对serialVersionUID的处理进行了了解,  
ObjectOutputStream.java调用writeObject的时候会调用到下面的代码:
 
这是调用ObjectStreamClass.java的writeNonProxy方法,写入非代理类的元数据信息
在写入类的元数据的时候会把serialVersionUID写入:

[java] 
 /**
    * Writes non-proxy class descriptor information to given output stream.
    */ 
   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()); 
    } 

   } 

在读取的时候会做几个部分的校验:
在ObjectInputStream.java的readObject方法时调用ObjectStreamClass.java的readNonProxy方法,
 
这里会读取suid = Long.valueOf(in.readLong());就是读取serialVersionUID,然后先做第一步校验if (isEnum && suid.longValue() != 0L) 如果是枚举类则serialVersionUID为0.

[java]
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(); 
    } 

然后下面还会对serialVersionUID进行下一步的验证:同样是在ObjectStreamClass.java的initNonProxy方法,suid = Long.valueOf(model.getSerialVersionUID());去除序列化后的model对象的serialVersionUID,if (serializable == localDesc.serializable &&!cl.isArray() &&suid.longValue() != localDesc.getSerialVersionUID()) 然后判断是否跟本地的class对象是否都是继承serializable 接口,并且cl不是数组,且serialVersionUID要跟当前序列化的class对象的serialVersionUID一致。

[java] 
/**
     * Initializes class descriptor representing a non-proxy class.
     */ 
    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;

补充:软件开发 , Java ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,