Android枚舉字段序列化

實(shí)體類實(shí)現(xiàn)Parcelable接口后枚舉字段該怎么寫?正好碰到這個(gè)問題,記錄一下。

枚舉類

public enum EnumBean {
    STEAM,
    EPIC
}

枚舉字段序列化,這里直接上寫法。實(shí)際上用了AS插件Android Parcelable Code Generator生成,當(dāng)然還是本著知其所以然的態(tài)度,思考一下為啥是這個(gè)寫法。

public class Test implements Parcelable {
    public String name;

    public int age;

    public EnumBean e;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(this.name);
        dest.writeInt(this.age);
        dest.writeInt(this.e == null ? -1 : this.e.ordinal());
    }

    public void readFromParcel(Parcel source) {
        this.name = source.readString();
        this.age = source.readInt();
        int tmpE = source.readInt();
        this.e = tmpE == -1 ? null : EnumBean.values()[tmpE];
    }

    public Test() {
    }

    protected Test(Parcel in) {
        this.name = in.readString();
        this.age = in.readInt();
        int tmpE = in.readInt();
        this.e = tmpE == -1 ? null : EnumBean.values()[tmpE];
    }

    public static final Parcelable.Creator<Test> CREATOR = new Parcelable.Creator<Test>() {
        @Override
        public Test createFromParcel(Parcel source) {
            return new Test(source);
        }

        @Override
        public Test[] newArray(int size) {
            return new Test[size];
        }
    };
}

其實(shí)從writeread字段e就可以看出,這里寫入的是枚舉類數(shù)組下標(biāo),讀取時(shí)根據(jù)下標(biāo)取出枚舉類實(shí)體。

dest.writeInt(this.e == null ? -1 : this.e.ordinal());

this.e = tmpE == -1 ? null : EnumBean.values()[tmpE];

眾所周知枚舉中的每個(gè)聲明都會(huì)創(chuàng)建枚舉類對(duì)象,ordinal()也就是枚舉中聲明的順序,對(duì)應(yīng)到枚舉類數(shù)組values()的下標(biāo)。

看一下編譯后的EnumBean.class文件字節(jié)碼

  //枚舉類默認(rèn)繼承Enum
  public final enum com/chenxuan/kotlin/EnumBean extends java/lang/Enum

  public final static enum Lcom/chenxuan/kotlin/EnumBean; STEAM

  public final static enum Lcom/chenxuan/kotlin/EnumBean; EPIC

  private final static synthetic [Lcom/chenxuan/kotlin/EnumBean; $VALUES

  //構(gòu)造方法
  private <init>(Ljava/lang/String;I)V
    L0
    LINENUMBER 3 L0
    ALOAD 0
    ALOAD 1
    ILOAD 2
    INVOKESPECIAL java/lang/Enum.<init> (Ljava/lang/String;I)V
    RETURN

  //static塊,創(chuàng)建聲明的枚舉類對(duì)象,枚舉類數(shù)組。
  static <clinit>()V
   L0
    LINENUMBER 4 L0
    NEW com/chenxuan/kotlin/EnumBean
    DUP
    LDC "STEAM"
    ICONST_0
    INVOKESPECIAL com/chenxuan/kotlin/EnumBean.<init> (Ljava/lang/String;I)V
    PUTSTATIC com/chenxuan/kotlin/EnumBean.STEAM : Lcom/chenxuan/kotlin/EnumBean;
   L1
    LINENUMBER 5 L1
    NEW com/chenxuan/kotlin/EnumBean
    DUP
    LDC "EPIC"
    ICONST_1
    INVOKESPECIAL com/chenxuan/kotlin/EnumBean.<init> (Ljava/lang/String;I)V
    PUTSTATIC com/chenxuan/kotlin/EnumBean.EPIC : Lcom/chenxuan/kotlin/EnumBean;
   L2
    LINENUMBER 3 L2
    ICONST_2
    ANEWARRAY com/chenxuan/kotlin/EnumBean
    DUP
    ICONST_0
    GETSTATIC com/chenxuan/kotlin/EnumBean.STEAM : Lcom/chenxuan/kotlin/EnumBean;
    AASTORE
    DUP
    ICONST_1
    GETSTATIC com/chenxuan/kotlin/EnumBean.EPIC : Lcom/chenxuan/kotlin/EnumBean;
    AASTORE
    PUTSTATIC com/chenxuan/kotlin/EnumBean.$VALUES : [Lcom/chenxuan/kotlin/EnumBean;
    RETURN

  public static values()[Lcom/chenxuan/kotlin/EnumBean;
   L0
    LINENUMBER 3 L0
    GETSTATIC com/chenxuan/kotlin/EnumBean.$VALUES : [Lcom/chenxuan/kotlin/EnumBean;
    INVOKEVIRTUAL [Lcom/chenxuan/kotlin/EnumBean;.clone ()Ljava/lang/Object;
    CHECKCAST [Lcom/chenxuan/kotlin/EnumBean;
    ARETURN

  public static valueOf(Ljava/lang/String;)Lcom/chenxuan/kotlin/EnumBean;
   L0
    LINENUMBER 3 L0
    LDC Lcom/chenxuan/kotlin/EnumBean;.class
    ALOAD 0
    INVOKESTATIC java/lang/Enum.valueOf (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
    CHECKCAST com/chenxuan/kotlin/EnumBean
    ARETURN

很好理解,聲明了兩個(gè)EnumBean類型的變量STEAM和EPIC并在static塊中初始化;同時(shí)聲明了EnumBean數(shù)組$VALUES,按照枚舉聲明順序添加到數(shù)組。

需注意枚舉變量初始化時(shí)調(diào)用的構(gòu)造方法傳入了兩個(gè)參數(shù):聲明的枚舉變量對(duì)應(yīng)的字符串STEAM、下標(biāo)0。

    LDC "STEAM"
    ICONST_0
    INVOKESPECIAL com/chenxuan/kotlin/EnumBean.<init> (Ljava/lang/String;I)V

EnumBean構(gòu)造方法調(diào)用父類Enum的構(gòu)造方法

  private <init>(Ljava/lang/String;I)V
    L0
    LINENUMBER 3 L0
    ALOAD 0
    ALOAD 1
    ILOAD 2
    INVOKESPECIAL java/lang/Enum.<init> (Ljava/lang/String;I)V
    RETURN

繼續(xù)看Enum的構(gòu)造方法

    private final String name;
    private final int ordinal;

    protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }

    public final int ordinal() {
        return ordinal;
    }

如此一來,ordinal就和枚舉聲明順序或者說枚舉數(shù)組下標(biāo)聯(lián)系起來了。

回看readFromParcelEnumBean.values()[tmpE],由上述字節(jié)碼可知values()方法調(diào)用$VALUES.clone()也就是枚舉類數(shù)組,然后根據(jù)數(shù)組下標(biāo)取出枚舉類實(shí)體。

還有我們常用的valueOf()方法,調(diào)用父類Enum.valueOf()傳入了EnumBean.class。

  public static valueOf(Ljava/lang/String;)Lcom/chenxuan/kotlin/EnumBean;
   L0
    LINENUMBER 3 L0
    LDC Lcom/chenxuan/kotlin/EnumBean;.class
    ALOAD 0
    INVOKESTATIC java/lang/Enum.valueOf (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
    CHECKCAST com/chenxuan/kotlin/EnumBean
    ARETURN

Enum.valueOf()

    public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        Objects.requireNonNull(enumType, "enumType == null");
        Objects.requireNonNull(enumType, "name == null");
        T[] values = getSharedConstants(enumType);
        if (values == null) {
            throw new IllegalArgumentException(enumType.toString() + " is not an enum type.");
        }

        for (int i = values.length - 1; i >= 0; --i) {
            T value = values[i];
            if (name.equals(value.name())) {
                return value;
            }
        }
        throw new IllegalArgumentException(
                "No enum constant " + enumType.getCanonicalName() + "." + name);
    }

Enum.getSharedConstants()根據(jù)傳入的class獲取枚舉類數(shù)組values

    public static <T extends Enum<T>> T[] getSharedConstants(Class<T> enumType) {
        return (T[]) sharedConstantsCache.get(enumType);
    }

    private static final BasicLruCache<Class<? extends Enum>, Object[]> sharedConstantsCache
            = new BasicLruCache<Class<? extends Enum>, Object[]>(64) {
        @Override protected Object[] create(Class<? extends Enum> enumType) {
            return enumValues(enumType);
        }
    };

    private static Object[] enumValues(Class<? extends Enum> clazz) {
        if (!clazz.isEnum()) {
            return null;
        }
        try {
            Method valueMethod = clazz.getDeclaredMethod("values");
            return (Object[]) valueMethod.invoke(null);
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

這里通過反射獲取到枚舉類數(shù)組,然后迭代數(shù)組找到name相同的枚舉類。而name其實(shí)就是聲明的枚舉變量對(duì)應(yīng)的字符串,在static塊中初始化時(shí)調(diào)用到父類Enum構(gòu)造方法賦值。

    NEW com/chenxuan/kotlin/EnumBean
    DUP
    LDC "STEAM"
    ICONST_0
    INVOKESPECIAL com/chenxuan/kotlin/EnumBean.<init> (Ljava/lang/String;I)V
    PUTSTATIC com/chenxuan/kotlin/EnumBean.STEAM : Lcom/chenxuan/kotlin/EnumBean;
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 當(dāng)我們使用的對(duì)象里有枚舉類型的字段,我們可能需要的是枚舉中不同的屬性。 比如,在進(jìn)行JSON序列化的時(shí)候,我們可能...
    awaa閱讀 6,334評(píng)論 0 1
  • 序列化 將數(shù)據(jù)結(jié)構(gòu)或?qū)ο筠D(zhuǎn)換成二進(jìn)制串的過程。 反序列化 將在序列化過程中所生成的二進(jìn)制串轉(zhuǎn)換成數(shù)據(jù)結(jié)構(gòu)或者對(duì)象的...
    壹元伍角叁分閱讀 405評(píng)論 1 1
  • 什么是序列化/反序列化? 簡(jiǎn)單來說就是將對(duì)象轉(zhuǎn)換為可以傳輸?shù)亩M(jìn)制流(二進(jìn)制序列)的過程,這樣我們就可以通過序列化...
    有腹肌的豌豆Z閱讀 2,123評(píng)論 0 0
  • 源碼 https://gitee.com/eric-tutorial/SpringCloud-multiple-g...
    捕風(fēng)的逍遙侯閱讀 3,957評(píng)論 0 0
  • 序列化 定義以及相關(guān)概念 由于在系統(tǒng)底層,數(shù)據(jù)的傳輸形式是簡(jiǎn)單的字節(jié)序列形式傳遞,即在底層,系統(tǒng)不認(rèn)識(shí)對(duì)象,只認(rèn)識(shí)...
    WaterYuan閱讀 269評(píng)論 0 0

友情鏈接更多精彩內(nèi)容