1. 程式人生 > >Java 日看一類(37)之IO包中的ObjectStreamField類

Java 日看一類(37)之IO包中的ObjectStreamField類

該類完成了Comparable<Object>介面

引入了

import java.lang.reflect.Field;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.reflect.misc.ReflectUtil;

該類的類頭註釋如下:

/**
 * A description of a Serializable field from a Serializable class.  An array
 * of ObjectStreamFields is used to declare the Serializable fields of a class.
* * @author Mike Warres * @author Roger Riggs * @see ObjectStreamClass * @since 1.2 */

大意如下:

該類是描述序列化類中序列化欄位的類

一般會用一個ObjectStreamField陣列來宣告一個類中的序列化欄位

該類含有如下的成員變數:

欄位名稱

private final String name;

欄位資料型別的JVM簽字(基礎資料型別標識)

private final String signature;

欄位資料型別

private final Class<?> type;

是否將序列化欄位值設定為非共享

private final boolean unshared;

欄位相應的對映(如果存在才會被賦值)

private final Field field;

封閉欄位偏移量

private int offset = 0;

該類含有如下的成員方法:

建構函式(傳入欄位名和欄位資料型別,預設可共享)

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();//獲得傳入資料型別的JVM簽名field = null; }

建構函式(default型別的,傳入的是簽名而不是型別)

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");
}
}

建構函式(給予對映的欄位,是否共享控制,對getType()方法返回值的控制(返回實際型別或基礎型別,或者是class類))

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;//如果該類的展示型別為真或者欄位型別為基礎型別則將欄位型別繫結到type 上,否則繫結Object.classsignature = getClassSignature(ftype).intern();//獲得該類的簽名}

獲得欄位名稱

public String getName() {
    return name;
}

獲得欄位型別

@CallerSensitive
public Class<?> getType() {
    if (System.getSecurityManager() != null) {//獲得控制檯安全管理器
        Class<?> caller = Reflection.getCallerClass();//獲得呼叫映像,native函式,看不到預設的呼叫型別        if (ReflectUtil.needsPackageAccessCheck(caller.getClassLoader(), type.getClassLoader())) {//判定兩個型別的ClassLoader是否相等或者為祖先關係(caller為type的祖先)
            ReflectUtil.checkPackageAccess(type);//如果該型別呼叫不可訪問的包則丟擲SecurityException}
    }
    return type;
}

獲得型別識別符號

public char getTypeCode() {
    return signature.charAt(0);//簽名中的第一位字元就可以分辨簽名型別,所以返回一個即可}

獲得型別的字串

public String getTypeString() {
    return isPrimitive() ? null : signature;//如果是基礎型別就不返回,非基礎型別返回型別簽名}

返回欄位偏移量

public int getOffset() {
    return offset;
}

設定欄位偏移量

protected void setOffset(int offset) {
    this.offset = offset;
}

判定型別是否為基礎型別

public boolean isPrimitive() {
    char tcode = signature.charAt(0);
    return ((tcode != 'L') && (tcode != '['));//對應關係可見上面的建構函式,或見下面的簽字獲取函式}

返回是否不可共享

public boolean isUnshared() {
    return unshared;
}

欄位名稱比較

public int compareTo(Object obj) {
    ObjectStreamField other = (ObjectStreamField) obj;//獲得傳入物件的流欄位    boolean isPrim = isPrimitive();
    if (isPrim != other.isPrimitive()) {//如果兩個不全為基礎型別或非基礎型別return isPrim ? -1 : 1;//如果當前值為基礎型別則返回-1(對應傳入值為非基礎),非基礎型別則返回1(對應傳入值為基礎)}
    return name.compareTo(other.name);//兩個型別全為基礎或非基礎,按照字典序比較兩個欄位的名字}

返回標準的欄位描述

public String toString() {
    return signature + ' ' + name;
}

返回該欄位的欄位型別對映(可能為空,如果沒有繫結對映的話)

Field getField() {
    return field;
}

返回型別簽字

String getSignature() {
    return signature;
}

獲得欄位簽字

private static String getClassSignature(Class<?> cl) {
    StringBuilder sbuf = new StringBuilder();//類似StingBuffer,可以理解為閹割版的,執行效率比StringBuffer高    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();//返回標準化後的型別簽字}

該類屬於‘常用類’(在封裝好的Object操作類中大量使用該類),該類實質上是類欄位的一種抽象化表現,但同時也和Field類有所不同,由於該類單純針對序列化欄位,所以提供的功能和屬性少於Field類,屬於一種更高層次的單一功能性抽象。