枚举原理与常见用法与技巧

枚举简介

首先是代替使用常量枚举方式,这种方式是最常用的的方式。 假设我们有一个payStatus,不同值分别代表的含义如下: 0-初始化,1-支付中,2-支付成功,3-支付失败。 我们先来看一个直接用连int型枚举常量都难得提供的方式:

public class Pay {
    
    private int payStatus;
    
    
    public int getPayStatus() {
        return payStatus;
    }

    public void setPayStatus(int payStatus) {
        this.payStatus = payStatus;
    }

    public static void main(String[] args) {
//        0-初始化,1-支付中,2-支付成功,3-支付失败
        Pay pay = new Pay();
        pay.setPayStatus(4);
        switch(pay.getPayStatus()){
        case 0: 
            System.out.println("初始化");
            break;
        case 1: 
            System.out.println("支付中");
            break;
        case 2: 
            System.out.println("支付成功");
            break;
        case 3: 
            System.out.println("支付失败");
            break;
        default:
            throw new IllegalStateException("错误的支付状态");
        }
    }

}

像上面的代码,对于使用者来说是非常不友好的,鬼知道0,1,2,3代表的是什么,猜测都不好猜,并且不好记忆,最严重的是没有限制。像上面完全可以把payStatus设置为4。

下面来一个提供int型枚举的方式:

public class Pay {
    
    /**
     * 支付初始化
     */
    public static final int INIT = 0;
    
    /**
     * 支付中
     */
    public static final int PAYING = 1;
    
    /**
     * 支付成功
     */
    public static final int SUCCESS = 2;
    
    /**
     * 支付失败
     */
    public static final int FAIL = 3;
    
    private int payStatus;
    
    
    public int getPayStatus() {
        return payStatus;
    }

    public void setPayStatus(int payStatus) {
        this.payStatus = payStatus;
    }

    public static void main(String[] args) {
//        0-初始化,1-支付中,2-支付成功,3-支付失败
        Pay pay = new Pay();
        pay.setPayStatus(PAYING);
        switch(pay.getPayStatus()){
        case 0: 
            System.out.println("初始化");
            break;
        case 1: 
            System.out.println("支付中");
            break;
        case 2: 
            System.out.println("支付成功");
            break;
        case 3: 
            System.out.println("支付失败");
            break;
        default:
            throw new IllegalStateException("错误的支付状态");
        }
    }

}

这种方式就常见的多了,我们在很多第三方库中都能看到这样的方式。这样对于习惯这样的模式的开发者就比较方便了,也方便记忆和使用。但是同样没有做限制。pay.setPayStatus(4);这样的调用方式,使得在运行时才抛出异常。

接下来我们看使用枚举的模式: 枚举类型:

public enum PayStatus {

    INIT(0,"初始化"),
    PAYING(1,"支付中"),
    SUCCESS(2,"支付成功"),
    FAIL(3,"支付失败");

    private Integer id;
    private String desc;
    
    private static final Map<Integer, PayStatus> idToEnum = new HashMap<Integer, PayStatus>();
    static {
        for (PayStatus op : values())
            idToEnum.put(op.id, op);
    }

    public static PayStatus getInstance(Integer id) {
        return idToEnum.get(id);
    }

    private PayStatus(Integer id, String desc){
        this.id = id;
        this.desc = desc;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    @Override
    public String toString() {
        return desc;
    }
}

对于枚举类型,最后使用实例域,不要使用枚举的默认序数ordinal,因为添加和交互顺序都可能改变ordinal,这样对于依赖以ordinal的客户端都会出错。所以添加实例域id来表示。 这里有2个小技巧:

  1. 缓存id与枚举的对应关系,并提供静态公有方法,因为很多时候需要通过id值获取枚举,比如说在数据库中存放枚举使用的是整形的id值,ORM时候需要转换int为枚举类型
  2. 重写toString,很多时候展示层希望显示的是desc描述字段,重写了toString就可以直接通过打印枚举类型就可以打印desc的字段的类容。
public class Pay {
    
    private PayStatus payStatus;
    
    public PayStatus getPayStatus() {
        return payStatus;
    }

    public void setPayStatus(PayStatus payStatus) {
        this.payStatus = payStatus;
    }

    public static void main(String[] args) {
//        0-初始化,1-支付中,2-支付成功,3-支付失败
        Pay pay = new Pay();
        pay.setPayStatus(PayStatus.PAYING);
        switch(pay.getPayStatus()){
        case INIT: 
            System.out.println("初始化");
            break;
        case PAYING: 
            System.out.println("支付中");
            break;
        case SUCCESS: 
            System.out.println("支付成功");
            break;
        case FAIL: 
            System.out.println("支付失败");
            break;
        default:
            throw new IllegalStateException("错误的支付状态");
        }
    }

}

我们把支付状态从int类型换成了PayStatus枚举类型,就限制了客户端传递错误的状态参数,客户端也可以很容易的从枚举类型PayStatus中选择需要的状态。

枚举与行为绑定

这个属于比较少见的,但是的确非常有潜力的使用方式,下面是Effictive Java中的一个例子:

import java.util.HashMap;
import java.util.Map;

public enum Operation {
    PLUS("+") {
        double apply(double x, double y) {
            return x + y;
        }
    },
    MINUS("-") {
        double apply(double x, double y) {
            return x - y;
        }
    },
    TIMES("*") {
        double apply(double x, double y) {
            return x * y;
        }
    },
    DIVIDE("/") {
        double apply(double x, double y) {
            return x / y;
        }
    };
    private final String symbol;

    Operation(String symbol) {
        this.symbol = symbol;
    }

    @Override
    public String toString() {
        return symbol;
    }

    abstract double apply(double x, double y);

    private static final Map<String, Operation> stringToEnum = new HashMap<String, Operation>();
    static {
        for (Operation op : values())
            stringToEnum.put(op.toString(), op);
    }

    public static Operation fromString(String symbol) {
        return stringToEnum.get(symbol);
    }

    public static void main(String[] args) {
        double x = 2;
        double y = 4;
        for (Operation op : Operation.values())
            System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
    }
}

这里主要主要的是这种方式,注意思考abstract double apply(double x, double y);抽象方法。

枚举原理

我们对上面的枚举类型PayStatus的class文件进行反编译(只看签名,不看字节码,只是用-private参数输出所有类和成员):

javap -private PayStatus

内容如下:

public final class cn.freemethod.type.PayStatus extends java.lang.Enum<cn.freemethod.type.PayStatus> {
  public static final cn.freemethod.type.PayStatus INIT;
  public static final cn.freemethod.type.PayStatus PAYING;
  public static final cn.freemethod.type.PayStatus SUCCESS;
  public static final cn.freemethod.type.PayStatus FAIL;
  private java.lang.Integer id;
  private java.lang.String desc;
  private static final java.util.Map<java.lang.Integer, cn.freemethod.type.PayStatus> idToEnum;
  private static final cn.freemethod.type.PayStatus[] ENUM$VALUES;
  static {};
  public static cn.freemethod.type.PayStatus getInstance(java.lang.Integer);
  private cn.freemethod.type.PayStatus(java.lang.String, int, java.lang.Integer, java.lang.String);
  public java.lang.Integer getId();
  public void setId(java.lang.Integer);
  public java.lang.String getDesc();
  public void setDesc(java.lang.String);
  public java.lang.String toString();
  public static cn.freemethod.type.PayStatus[] values();
  public static cn.freemethod.type.PayStatus valueOf(java.lang.String);
}

从上面PayStatus反编译的代码来看,Java枚举就是一个语法糖,本质上还是被编译为了class,只不过这个类继承了Enum类,并且包含了自身的引用做为枚举值。 这里并没有输出字节码,如果使用(-verbose或者-c参数):

javap -verbose PayStatus

输出字节码就会发现在static初始化阶段,通过调用valueOf(String name)这个静态方法为INIT; PAYING; SUCCESS; FAIL;这些枚举值赋值。valueOf调用了Enum的静态方法

public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name)
public static cn.freemethod.type.PayStatus valueOf(java.lang.String);

从上面的方法反编译的字节码中我们看到了把PayStatus.class传给了Enum的valueOf。 调用的线大概就是下面的样子: PayStatus.valueOf->Enum.valueOf->Class.enumConstantDirectory->Class.getEnumConstantsShared->PayStatus.values 上面这个有一点抽象,我们来理一理。从字节码中(见附录)可以看出PayStatus枚举(enum)被编译为了类(Class),并且继承了Enum类,注意Enum是类(Class)类型,而不是枚举(enum)类型,并且把每一个枚举都编译为了一个自身类型的静态引用,并且在static中初始化的,从初始化字节码中可以看到传递了4个参数。其中2个是中enum中定义的id和desc,另外另个是编译器生成的name和ordinal。在调用PayStatus构造的时候把name和ordinal传递给了Enum构造函数。 另外,在初始化的时候,实例化了每一个枚举代表的类,并且把这些枚举代表的类的实例保存到了一个Enum数组中。

从上面的字节码签名以及分析中可以看到枚举被编译成为了,饿汉式的工厂类,有多少个枚举就初始化多少个类。然后就可以通过类或者静态工厂方法获取相应的实例。

注意:上面原理没有理清楚没有关系,但是注意下面这2条

  1. name代表的是枚举中的类型(字面量),就是被编译为类之后的自身的引用,像PayStatus中的INIT、PAYING、SUCCESS、FAIL,使用枚举的valueOf(String name)获取枚举使用的name就是这个name,枚举类的name()方法获取的值也是这个。
  2. ordinal是编译器生成的从0开始,第一个是0,第2个是1,以此类推。

EnumSet

如果一个枚举类型主要用在集合中,一般使用int枚举模式,并且将2的不同倍数赋予每一个常量。最著名的就是java.lang.reflect.Modifier类。另外一个比较经典的例子是在枚举中使用的fastjson的com.alibaba.fastjson.serializer.SerializerFeature这个类。关于SerializerFeature可以参考:SerializerFeature

下面看一个使用EnumSet改造的SerializerFeature类:

import java.util.EnumSet;

public enum SerializerFeature {
    QuoteFieldNames,
    /**
     * 
     */
    UseSingleQuotes,
    /**
     * 
     */
    WriteMapNullValue,
    /**
     * 用枚举toString()值输出
     */
    WriteEnumUsingToString,
    /**
     * 用枚举name()输出
     */
    WriteEnumUsingName,
    /**
     * 
     */
    UseISO8601DateFormat,
    /**
     * @since 1.1
     */
    WriteNullListAsEmpty,
    /**
     * @since 1.1
     */
    WriteNullStringAsEmpty,
    /**
     * @since 1.1
     */
    WriteNullNumberAsZero,
    /**
     * @since 1.1
     */
    WriteNullBooleanAsFalse,
    /**
     * @since 1.1
     */
    SkipTransientField,
    /**
     * @since 1.1
     */
    SortField,
    /**
     * @since 1.1.1
     */
    @Deprecated
    WriteTabAsSpecial,
    /**
     * @since 1.1.2
     */
    PrettyFormat,
    /**
     * @since 1.1.2
     */
    WriteClassName,

    /**
     * @since 1.1.6
     */
    DisableCircularReferenceDetect,

    /**
     * @since 1.1.9
     */
    WriteSlashAsSpecial,

    /**
     * @since 1.1.10
     */
    BrowserCompatible,

    /**
     * @since 1.1.14
     */
    WriteDateUseDateFormat,

    /**
     * @since 1.1.15
     */
    NotWriteRootClassName,

    /**
     * @since 1.1.19
     */
    DisableCheckSpecialChar,

    /**
     * @since 1.1.35
     */
    BeanToArray,

    /**
     * @since 1.1.37
     */
    WriteNonStringKeyAsString,
    
    /**
     * @since 1.1.42
     */
    NotWriteDefaultValue,
    
    /**
     * @since 1.2.6
     */
    BrowserSecure,
    
    /**
     * @since 1.2.7
     */
    IgnoreNonFieldGetter;

    public static boolean isEnabled(EnumSet<SerializerFeature> features, SerializerFeature feature) {
        return features.contains(feature);
    }
    
    public static boolean isEnabled(EnumSet<SerializerFeature> features, EnumSet<SerializerFeature> fieaturesB, SerializerFeature feature) {
        return features.contains(feature) || fieaturesB.contains(feature);
    }

    public static EnumSet<SerializerFeature> config(EnumSet<SerializerFeature> features, SerializerFeature feature, boolean state) {
        if (state) {
            features.add(feature);
        } else {
            features.remove(feature);
        }
        return features;
    }
    
    public static EnumSet<SerializerFeature> of(SerializerFeature[] features) {
        EnumSet<SerializerFeature> result = EnumSet.noneOf(SerializerFeature.class);
        if (features == null) {
            return result;
        }
        
        for (SerializerFeature feature: features) {
            result.add(feature);
        }
        return result;
    }
}

上面改造的已经改变了接口,只是为了介绍EnumSet的使用。如果觉得上面的例子有一点晦涩,再看一下下面的简单的例子,假设有一个资源包,包含n中语言,怎样设计这个语言的枚举类型呢?可以参考下面的例子:

import java.util.EnumSet;

public enum Language {
    
    CHINESE,
    ENGLISH,
    JAPANESE,
    FRENCH,
    ARABIC;
    
    /**
     * languages是否包含language
     * @param languages
     * @param language
     * @return
     */
    public static boolean isEnabled(EnumSet<Language> languages, Language language) {
        return languages.contains(language);
    }
    
    /**
     * 检查language是否包含在languages中或者languagesB中
     * @param languages
     * @param languagesB
     * @param language
     * @return
     */
    public static boolean isEnabled(EnumSet<Language> languages, EnumSet<Language> languagesB, Language language) {
        return languages.contains(language) || languagesB.contains(language);
    }

    /**
     * 如果state为true就在languages中添加language语言
     * 如果state为false就从languages中移除language语言
     * @param languages
     * @param language
     * @param state
     * @return
     */
    public static EnumSet<Language> config(EnumSet<Language> languages, Language language, boolean state) {
        if (state) {
            languages.add(language);
        } else {
            languages.remove(language);
        }
        return languages;
    }
    
    /**
     * 从languages数组中获取枚举集合
     * @param languages
     * @return
     */
    public static EnumSet<Language> of(Language[] languages) {
        EnumSet<Language> result = EnumSet.noneOf(Language.class);
        if (languages == null) {
            return result;
        }
        
        for (Language language: languages) {
            result.add(language);
        }
        return result;
    }

}

当资源包包含多种语言的时候使用EnumSet就非常方便。当然如果要在数据库中存放一个整形的话,还是考虑一下使用int型来做位运算吧。

EnumMap

EnumMap从名字就知道是针对枚举的map,就是枚举到值的映射。感觉和HashMap很像,但是针对枚举做了优化,如果map的键是枚举类型,优先考虑EnumMap。 下面还是列一个Effective Java中的例子:

import java.util.EnumMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

public class Herb {
    public enum Type {
        ANNUAL, PERENNIAL, BIENNIAL
    }

    private final String name;
    private final Type type;

    Herb(String name, Type type) {
        this.name = name;
        this.type = type;
    }

    @Override
    public String toString() {
        return name;
    }

    public static void main(String[] args) {
        Herb[] garden = { new Herb("Basil", Type.ANNUAL),
                new Herb("Carroway", Type.BIENNIAL),
                new Herb("Dill", Type.ANNUAL),
                new Herb("Lavendar", Type.PERENNIAL),
                new Herb("Parsley", Type.BIENNIAL),
                new Herb("Rosemary", Type.PERENNIAL) };

        Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<Herb.Type, Set<Herb>>(Herb.Type.class);
//      Map<Herb.Type, Set<Herb>> herbsByType = new HashMap<Herb.Type, Set<Herb>>();
        
        for (Herb.Type t : Herb.Type.values())
            herbsByType.put(t, new HashSet<Herb>());
        for (Herb h : garden)
            herbsByType.get(h.type).add(h);
        System.out.println(herbsByType);
    }
}

枚举的扩展

枚举是不能被继承的,从上面的分析也知道,枚举是一个语法糖被编译为了final类型的Class,所以显然是不能被继承的。但是枚举可以实现接口,虽然这种方式很少间,但是是值得思考的,可以考虑应用到策略和状态模式之中。 这个还是列一个Efficient Java中的例子来看一下:

public interface Operation {
    double apply(double x, double y);
}
import java.util.Arrays;
import java.util.Collection;

public enum ExtendedOperation implements Operation {
    EXP("^") {
        public double apply(double x, double y) {
            return Math.pow(x, y);
        }
    },
    REMAINDER("%") {
        public double apply(double x, double y) {
            return x % y;
        }
    };

    private final String symbol;

    ExtendedOperation(String symbol) {
        this.symbol = symbol;
    }

    @Override
    public String toString() {
        return symbol;
    }

    public static void main(String[] args) {
        double x = 2;
        double y = 4;
        test1(ExtendedOperation.class, x, y);

        System.out.println();
        test2(Arrays.asList(ExtendedOperation.values()), x, y);
    }

    /**
     * T 类型必须继承之Enum,并且是Operation类型(实现Operation接口)
     * @param opSet
     * @param x
     * @param y
     */
    private static <T extends Enum<T> & Operation> void test1(Class<T> opSet,
            double x, double y) {
        //getEnumConstants()方法是获取所有的枚举常量,就是class类型枚举类型的实例
        for (Operation op : opSet.getEnumConstants())
            System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
    }

    private static void test2(Collection<? extends Operation> opSet, double x,
            double y) {
        for (Operation op : opSet)
            System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
    }
}

总结

  1. 枚举的构造方法是私有的(或者包)
  2. 尽量不要利用枚举的序数ordinal
  3. 考虑缓存id与枚举的map
  4. 弄清楚name、ordinal和valueOf代表的含义
  5. 枚举是不能被继承的,但是可以实现接口,可以通过实现接口扩展

附录:Paystatus字节码

下面的字节码是上面的PayStatus.java编译为class后反编译得到的:

javap -s -private -verbose PayStatus

使用-s是为了输出签名(括号中是参数,后面是返回值。例如:(Ljava/lang/Integer;)Lcn/freemethod/type/PayStatus表示的是参数是一个Integer类型的类(L开头),返回值是PayStatus类),-private是为了输出所有的成员,因为枚举的构造方法是私有的。使用-verbose是为了输出字节码,也可以使用-c代替。可以使用下面的命令重定向到文件:

javap -s -private -verbose PayStatus>PayStatus.txt
  MD5 checksum 052bf11bd45bc1e2d573f3cd6a179ac1
  Compiled from "PayStatus.java"
public final class cn.freemethod.type.PayStatus extends java.lang.Enum<cn.freemethod.type.PayStatus>
  SourceFile: "PayStatus.java"
  Signature: #111                         // Ljava/lang/Enum<Lcn/freemethod/type/PayStatus;>;
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM

Constant pool:
    #1 = Class              #2            //  cn/freemethod/type/PayStatus
    #2 = Utf8               cn/freemethod/type/PayStatus
    #3 = Class              #4            //  java/lang/Enum
    #4 = Utf8               java/lang/Enum
    #5 = Utf8               INIT
    #6 = Utf8               Lcn/freemethod/type/PayStatus;
    #7 = Utf8               PAYING
    #8 = Utf8               SUCCESS
    #9 = Utf8               FAIL
   #10 = Utf8               id
   #11 = Utf8               Ljava/lang/Integer;
   #12 = Utf8               desc
   #13 = Utf8               Ljava/lang/String;
   #14 = Utf8               idToEnum
   #15 = Utf8               Ljava/util/Map;
   #16 = Utf8               Signature
   #17 = Utf8               Ljava/util/Map<Ljava/lang/Integer;Lcn/freemethod/type/PayStatus;>;
   #18 = Utf8               ENUM$VALUES
   #19 = Utf8               [Lcn/freemethod/type/PayStatus;
   #20 = Utf8               <clinit>
   #21 = Utf8               ()V
   #22 = Utf8               Code
   #23 = String             #5            //  INIT
   #24 = Methodref          #25.#27       //  java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #25 = Class              #26           //  java/lang/Integer
   #26 = Utf8               java/lang/Integer
   #27 = NameAndType        #28:#29       //  valueOf:(I)Ljava/lang/Integer;
   #28 = Utf8               valueOf
   #29 = Utf8               (I)Ljava/lang/Integer;
   #30 = String             #31           //  初始化
   #31 = Utf8               初始化
   #32 = Methodref          #1.#33        //  cn/freemethod/type/PayStatus."<init>":(Ljava/lang/String;ILjava/lang/Integer;Ljava/lang/String;)V
   #33 = NameAndType        #34:#35       //  "<init>":(Ljava/lang/String;ILjava/lang/Integer;Ljava/lang/String;)V
   #34 = Utf8               <init>
   #35 = Utf8               (Ljava/lang/String;ILjava/lang/Integer;Ljava/lang/String;)V
   #36 = Fieldref           #1.#37        //  cn/freemethod/type/PayStatus.INIT:Lcn/freemethod/type/PayStatus;
   #37 = NameAndType        #5:#6         //  INIT:Lcn/freemethod/type/PayStatus;
   #38 = String             #7            //  PAYING
   #39 = String             #40           //  支付中
   #40 = Utf8               支付中
   #41 = Fieldref           #1.#42        //  cn/freemethod/type/PayStatus.PAYING:Lcn/freemethod/type/PayStatus;
   #42 = NameAndType        #7:#6         //  PAYING:Lcn/freemethod/type/PayStatus;
   #43 = String             #8            //  SUCCESS
   #44 = String             #45           //  支付成功
   #45 = Utf8               支付成功
   #46 = Fieldref           #1.#47        //  cn/freemethod/type/PayStatus.SUCCESS:Lcn/freemethod/type/PayStatus;
   #47 = NameAndType        #8:#6         //  SUCCESS:Lcn/freemethod/type/PayStatus;
   #48 = String             #9            //  FAIL
   #49 = String             #50           //  支付失败
   #50 = Utf8               支付失败
   #51 = Fieldref           #1.#52        //  cn/freemethod/type/PayStatus.FAIL:Lcn/freemethod/type/PayStatus;
   #52 = NameAndType        #9:#6         //  FAIL:Lcn/freemethod/type/PayStatus;
   #53 = Fieldref           #1.#54        //  cn/freemethod/type/PayStatus.ENUM$VALUES:[Lcn/freemethod/type/PayStatus;
   #54 = NameAndType        #18:#19       //  ENUM$VALUES:[Lcn/freemethod/type/PayStatus;
   #55 = Class              #56           //  java/util/HashMap
   #56 = Utf8               java/util/HashMap
   #57 = Methodref          #55.#58       //  java/util/HashMap."<init>":()V
   #58 = NameAndType        #34:#21       //  "<init>":()V
   #59 = Fieldref           #1.#60        //  cn/freemethod/type/PayStatus.idToEnum:Ljava/util/Map;
   #60 = NameAndType        #14:#15       //  idToEnum:Ljava/util/Map;
   #61 = Methodref          #1.#62        //  cn/freemethod/type/PayStatus.values:()[Lcn/freemethod/type/PayStatus;
   #62 = NameAndType        #63:#64       //  values:()[Lcn/freemethod/type/PayStatus;
   #63 = Utf8               values
   #64 = Utf8               ()[Lcn/freemethod/type/PayStatus;
   #65 = Fieldref           #1.#66        //  cn/freemethod/type/PayStatus.id:Ljava/lang/Integer;
   #66 = NameAndType        #10:#11       //  id:Ljava/lang/Integer;
   #67 = InterfaceMethodref #68.#70       //  java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   #68 = Class              #69           //  java/util/Map
   #69 = Utf8               java/util/Map
   #70 = NameAndType        #71:#72       //  put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   #71 = Utf8               put
   #72 = Utf8               (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
   #73 = Utf8               LineNumberTable
   #74 = Utf8               LocalVariableTable
   #75 = Utf8               op
   #76 = Utf8               StackMapTable
   #77 = Class              #19           //  "[Lcn/freemethod/type/PayStatus;"
   #78 = Utf8               getInstance
   #79 = Utf8               (Ljava/lang/Integer;)Lcn/freemethod/type/PayStatus;
   #80 = InterfaceMethodref #68.#81       //  java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
   #81 = NameAndType        #82:#83       //  get:(Ljava/lang/Object;)Ljava/lang/Object;
   #82 = Utf8               get
   #83 = Utf8               (Ljava/lang/Object;)Ljava/lang/Object;
   #84 = Methodref          #3.#85        //  java/lang/Enum."<init>":(Ljava/lang/String;I)V
   #85 = NameAndType        #34:#86       //  "<init>":(Ljava/lang/String;I)V
   #86 = Utf8               (Ljava/lang/String;I)V
   #87 = Fieldref           #1.#88        //  cn/freemethod/type/PayStatus.desc:Ljava/lang/String;
   #88 = NameAndType        #12:#13       //  desc:Ljava/lang/String;
   #89 = Utf8               this
   #90 = Utf8               getId
   #91 = Utf8               ()Ljava/lang/Integer;
   #92 = Utf8               setId
   #93 = Utf8               (Ljava/lang/Integer;)V
   #94 = Utf8               getDesc
   #95 = Utf8               ()Ljava/lang/String;
   #96 = Utf8               setDesc
   #97 = Utf8               (Ljava/lang/String;)V
   #98 = Utf8               toString
   #99 = Methodref          #100.#102     //  java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
  #100 = Class              #101          //  java/lang/System
  #101 = Utf8               java/lang/System
  #102 = NameAndType        #103:#104     //  arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
  #103 = Utf8               arraycopy
  #104 = Utf8               (Ljava/lang/Object;ILjava/lang/Object;II)V
  #105 = Utf8               (Ljava/lang/String;)Lcn/freemethod/type/PayStatus;
  #106 = Methodref          #3.#107       //  java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
  #107 = NameAndType        #28:#108      //  valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
  #108 = Utf8               (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
  #109 = Utf8               SourceFile
  #110 = Utf8               PayStatus.java
  #111 = Utf8               Ljava/lang/Enum<Lcn/freemethod/type/PayStatus;>;
{
  public static final cn.freemethod.type.PayStatus INIT;
    Signature: Lcn/freemethod/type/PayStatus;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM


  public static final cn.freemethod.type.PayStatus PAYING;
    Signature: Lcn/freemethod/type/PayStatus;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM


  public static final cn.freemethod.type.PayStatus SUCCESS;
    Signature: Lcn/freemethod/type/PayStatus;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM


  public static final cn.freemethod.type.PayStatus FAIL;
    Signature: Lcn/freemethod/type/PayStatus;
    flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM


  private java.lang.Integer id;
    Signature: Ljava/lang/Integer;
    flags: ACC_PRIVATE


  private java.lang.String desc;
    Signature: Ljava/lang/String;
    flags: ACC_PRIVATE


  private static final java.util.Map<java.lang.Integer, cn.freemethod.type.PayStatus> idToEnum;
    Signature: Ljava/util/Map;
    flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL

    Signature: #17                          // Ljava/util/Map<Ljava/lang/Integer;Lcn/freemethod/type/PayStatus;>;

  private static final cn.freemethod.type.PayStatus[] ENUM$VALUES;
    Signature: [Lcn/freemethod/type/PayStatus;
    flags: ACC_PRIVATE, ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC


  static {};
    Signature: ()V
    flags: ACC_STATIC

    Code:
      stack=6, locals=4, args_size=0
         0: new           #1                  // class cn/freemethod/type/PayStatus
         3: dup           
         4: ldc           #23                 // String INIT
         6: iconst_0      
         7: iconst_0      
         8: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        11: ldc           #30                 // String 初始化
        13: invokespecial #32                 // Method "<init>":(Ljava/lang/String;ILjava/lang/Integer;Ljava/lang/String;)V
        16: putstatic     #36                 // Field INIT:Lcn/freemethod/type/PayStatus;
        19: new           #1                  // class cn/freemethod/type/PayStatus
        22: dup           
        23: ldc           #38                 // String PAYING
        25: iconst_1      
        26: iconst_1      
        27: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        30: ldc           #39                 // String 支付中
        32: invokespecial #32                 // Method "<init>":(Ljava/lang/String;ILjava/lang/Integer;Ljava/lang/String;)V
        35: putstatic     #41                 // Field PAYING:Lcn/freemethod/type/PayStatus;
        38: new           #1                  // class cn/freemethod/type/PayStatus
        41: dup           
        42: ldc           #43                 // String SUCCESS
        44: iconst_2      
        45: iconst_2      
        46: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        49: ldc           #44                 // String 支付成功
        51: invokespecial #32                 // Method "<init>":(Ljava/lang/String;ILjava/lang/Integer;Ljava/lang/String;)V
        54: putstatic     #46                 // Field SUCCESS:Lcn/freemethod/type/PayStatus;
        57: new           #1                  // class cn/freemethod/type/PayStatus
        60: dup           
        61: ldc           #48                 // String FAIL
        63: iconst_3      
        64: iconst_3      
        65: invokestatic  #24                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        68: ldc           #49                 // String 支付失败
        70: invokespecial #32                 // Method "<init>":(Ljava/lang/String;ILjava/lang/Integer;Ljava/lang/String;)V
        73: putstatic     #51                 // Field FAIL:Lcn/freemethod/type/PayStatus;
        76: iconst_4      
        77: anewarray     #1                  // class cn/freemethod/type/PayStatus
        80: dup           
        81: iconst_0      
        82: getstatic     #36                 // Field INIT:Lcn/freemethod/type/PayStatus;
        85: aastore       
        86: dup           
        87: iconst_1      
        88: getstatic     #41                 // Field PAYING:Lcn/freemethod/type/PayStatus;
        91: aastore       
        92: dup           
        93: iconst_2      
        94: getstatic     #46                 // Field SUCCESS:Lcn/freemethod/type/PayStatus;
        97: aastore       
        98: dup           
        99: iconst_3      
       100: getstatic     #51                 // Field FAIL:Lcn/freemethod/type/PayStatus;
       103: aastore       
       104: putstatic     #53                 // Field ENUM$VALUES:[Lcn/freemethod/type/PayStatus;
       107: new           #55                 // class java/util/HashMap
       110: dup           
       111: invokespecial #57                 // Method java/util/HashMap."<init>":()V
       114: putstatic     #59                 // Field idToEnum:Ljava/util/Map;
       117: invokestatic  #61                 // Method values:()[Lcn/freemethod/type/PayStatus;
       120: dup           
       121: astore_3      
       122: arraylength   
       123: istore_2      
       124: iconst_0      
       125: istore_1      
       126: goto          150
       129: aload_3       
       130: iload_1       
       131: aaload        
       132: astore_0      
       133: getstatic     #59                 // Field idToEnum:Ljava/util/Map;
       136: aload_0       
       137: getfield      #65                 // Field id:Ljava/lang/Integer;
       140: aload_0       
       141: invokeinterface #67,  3           // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
       146: pop           
       147: iinc          1, 1
       150: iload_1       
       151: iload_2       
       152: if_icmplt     129
       155: return        
      LineNumberTable:
        line 13: 0
        line 14: 19
        line 15: 38
        line 16: 57
        line 21: 107
        line 23: 117
        line 24: 133
        line 23: 147
        line 25: 155
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
             133      14     0    op   Lcn/freemethod/type/PayStatus;
      StackMapTable: number_of_entries = 2
           frame_type = 255 /* full_frame */
          offset_delta = 129
          locals = [ top, int, int, class "[Lcn/freemethod/type/PayStatus;" ]
          stack = []
           frame_type = 20 /* same */


  public static cn.freemethod.type.PayStatus getInstance(java.lang.Integer);
    Signature: (Ljava/lang/Integer;)Lcn/freemethod/type/PayStatus;
    flags: ACC_PUBLIC, ACC_STATIC

    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #59                 // Field idToEnum:Ljava/util/Map;
         3: aload_0       
         4: invokeinterface #80,  2           // InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
         9: checkcast     #1                  // class cn/freemethod/type/PayStatus
        12: areturn       
      LineNumberTable:
        line 28: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      13     0    id   Ljava/lang/Integer;

  private cn.freemethod.type.PayStatus(java.lang.String, int, java.lang.Integer, java.lang.String);
    Signature: (Ljava/lang/String;ILjava/lang/Integer;Ljava/lang/String;)V
    flags: ACC_PRIVATE

    Code:
      stack=3, locals=5, args_size=5
         0: aload_0       
         1: aload_1       
         2: iload_2       
         3: invokespecial #84                 // Method java/lang/Enum."<init>":(Ljava/lang/String;I)V
         6: aload_0       
         7: aload_3       
         8: putfield      #65                 // Field id:Ljava/lang/Integer;
        11: aload_0       
        12: aload         4
        14: putfield      #87                 // Field desc:Ljava/lang/String;
        17: return        
      LineNumberTable:
        line 31: 0
        line 32: 6
        line 33: 11
        line 34: 17
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0      18     0  this   Lcn/freemethod/type/PayStatus;
               0      18     3    id   Ljava/lang/Integer;
               0      18     4  desc   Ljava/lang/String;

  public java.lang.Integer getId();
    Signature: ()Ljava/lang/Integer;
    flags: ACC_PUBLIC

    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: getfield      #65                 // Field id:Ljava/lang/Integer;
         4: areturn       
      LineNumberTable:
        line 37: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       5     0  this   Lcn/freemethod/type/PayStatus;

  public void setId(java.lang.Integer);
    Signature: (Ljava/lang/Integer;)V
    flags: ACC_PUBLIC

    Code:
      stack=2, locals=2, args_size=2
         0: aload_0       
         1: aload_1       
         2: putfield      #65                 // Field id:Ljava/lang/Integer;
         5: return        
      LineNumberTable:
        line 41: 0
        line 42: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       6     0  this   Lcn/freemethod/type/PayStatus;
               0       6     1    id   Ljava/lang/Integer;

  public java.lang.String getDesc();
    Signature: ()Ljava/lang/String;
    flags: ACC_PUBLIC

    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: getfield      #87                 // Field desc:Ljava/lang/String;
         4: areturn       
      LineNumberTable:
        line 45: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       5     0  this   Lcn/freemethod/type/PayStatus;

  public void setDesc(java.lang.String);
    Signature: (Ljava/lang/String;)V
    flags: ACC_PUBLIC

    Code:
      stack=2, locals=2, args_size=2
         0: aload_0       
         1: aload_1       
         2: putfield      #87                 // Field desc:Ljava/lang/String;
         5: return        
      LineNumberTable:
        line 49: 0
        line 50: 5
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       6     0  this   Lcn/freemethod/type/PayStatus;
               0       6     1  desc   Ljava/lang/String;

  public java.lang.String toString();
    Signature: ()Ljava/lang/String;
    flags: ACC_PUBLIC

    Code:
      stack=1, locals=1, args_size=1
         0: aload_0       
         1: getfield      #87                 // Field desc:Ljava/lang/String;
         4: areturn       
      LineNumberTable:
        line 54: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       5     0  this   Lcn/freemethod/type/PayStatus;

  public static cn.freemethod.type.PayStatus[] values();
    Signature: ()[Lcn/freemethod/type/PayStatus;
    flags: ACC_PUBLIC, ACC_STATIC

    Code:
      stack=5, locals=3, args_size=0
         0: getstatic     #53                 // Field ENUM$VALUES:[Lcn/freemethod/type/PayStatus;
         3: dup           
         4: astore_0      
         5: iconst_0      
         6: aload_0       
         7: arraylength   
         8: dup           
         9: istore_1      
        10: anewarray     #1                  // class cn/freemethod/type/PayStatus
        13: dup           
        14: astore_2      
        15: iconst_0      
        16: iload_1       
        17: invokestatic  #99                 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
        20: aload_2       
        21: areturn       
      LineNumberTable:
        line 1: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature

  public static cn.freemethod.type.PayStatus valueOf(java.lang.String);
    Signature: (Ljava/lang/String;)Lcn/freemethod/type/PayStatus;
    flags: ACC_PUBLIC, ACC_STATIC

    Code:
      stack=2, locals=1, args_size=1
         0: ldc           #1                  // class cn/freemethod/type/PayStatus
         2: aload_0       
         3: invokestatic  #106                // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
         6: checkcast     #1                  // class cn/freemethod/type/PayStatus
         9: areturn       
      LineNumberTable:
        line 1: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
}

转载于:https://my.oschina.net/u/2474629/blog/840457

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值