您的位置:首页 > 编程语言 > Java开发

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

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

枚举简介

首先是代替使用常量枚举方式,这种方式是最常用的的方式。
假设我们有一个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个小技巧:

缓存id与枚举的对应关系,并提供静态公有方法,因为很多时候需要通过id值获取枚举,比如说在数据库中存放枚举使用的是整形的id值,ORM时候需要转换int为枚举类型

重写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条

name代表的是枚举中的类型(字面量),就是被编译为类之后的自身的引用,像PayStatus中的INIT、PAYING、SUCCESS、FAIL,使用枚举的valueOf(String name)获取枚举使用的name就是这个name,枚举类的name()方法获取的值也是这个。

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

总结

枚举的构造方法是私有的(或者包)

尽量不要利用枚举的序数ordinal

考虑缓存id与枚举的map

弄清楚name、ordinal和valueOf代表的含义

枚举是不能被继承的,但是可以实现接口,可以通过实现接口扩展

附录: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
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java枚举 EnumSet EnumMap