枚举原理与常见用法与技巧
博客专区 > trayvon 的博客 > 博客详情
枚举原理与常见用法与技巧
trayvon 发表于8个月前
枚举原理与常见用法与技巧
  • 发表于 8个月前
  • 阅读 2
  • 收藏 0
  • 点赞 0
  • 评论 0

腾讯云 十分钟定制你的第一个小程序>>>   

摘要: 我敢肯定,枚举大多数同学都非常熟悉了,但是我也相信很多同学使用枚举的模式都是非常一致的,很多时候都是直接代替常量枚举使用。 记住最常用的的这没有毛病,这里就是简单的介绍一些最常用的的模式和一些本来很好用但是却很少用的技巧,另外还有一些常见的坑。

枚举简介

首先是代替使用常量枚举方式,这种方式是最常用的的方式。 假设我们有一个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
}
共有 人打赏支持
粉丝 12
博文 89
码字总数 137187
作品 1
×
trayvon
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: