array(2) { ["docs"]=> array(10) { [0]=> array(10) { ["id"]=> string(3) "428" ["text"]=> string(77) "Visual Studio 2017 单独启动MSDN帮助(Microsoft Help Viewer)的方法" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(8) "DonetRen" ["tagsname"]=> string(55) "Visual Studio 2017|MSDN帮助|C#程序|.NET|Help Viewer" ["tagsid"]=> string(23) "[401,402,403,"300",404]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400964" ["_id"]=> string(3) "428" } [1]=> array(10) { ["id"]=> string(3) "427" ["text"]=> string(42) "npm -v;报错 cannot find module "wrapp"" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "zzty" ["tagsname"]=> string(50) "node.js|npm|cannot find module "wrapp“|node" ["tagsid"]=> string(19) "[398,"239",399,400]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400760" ["_id"]=> string(3) "427" } [2]=> array(10) { ["id"]=> string(3) "426" ["text"]=> string(54) "说说css中pt、px、em、rem都扮演了什么角色" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(12) "zhengqiaoyin" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511400640" ["_id"]=> string(3) "426" } [3]=> array(10) { ["id"]=> string(3) "425" ["text"]=> string(83) "深入学习JS执行--创建执行上下文(变量对象,作用域链,this)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "Ry-yuan" ["tagsname"]=> string(33) "Javascript|Javascript执行过程" ["tagsid"]=> string(13) "["169","191"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511399901" ["_id"]=> string(3) "425" } [4]=> array(10) { ["id"]=> string(3) "424" ["text"]=> string(30) "C# 排序技术研究与对比" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "vveiliang" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(8) ".Net Dev" ["catesid"]=> string(5) "[199]" ["createtime"]=> string(10) "1511399150" ["_id"]=> string(3) "424" } [5]=> array(10) { ["id"]=> string(3) "423" ["text"]=> string(72) "【算法】小白的算法笔记:快速排序算法的编码和优化" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(9) "penghuwan" ["tagsname"]=> string(6) "算法" ["tagsid"]=> string(7) "["344"]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511398109" ["_id"]=> string(3) "423" } [6]=> array(10) { ["id"]=> string(3) "422" ["text"]=> string(64) "JavaScript数据可视化编程学习(二)Flotr2,雷达图" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "chengxs" ["tagsname"]=> string(28) "数据可视化|前端学习" ["tagsid"]=> string(9) "[396,397]" ["catesname"]=> string(18) "前端基本知识" ["catesid"]=> string(5) "[198]" ["createtime"]=> string(10) "1511397800" ["_id"]=> string(3) "422" } [7]=> array(10) { ["id"]=> string(3) "421" ["text"]=> string(36) "C#表达式目录树(Expression)" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(4) "wwym" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(4) ".NET" ["catesid"]=> string(7) "["119"]" ["createtime"]=> string(10) "1511397474" ["_id"]=> string(3) "421" } [8]=> array(10) { ["id"]=> string(3) "420" ["text"]=> string(47) "数据结构 队列_队列实例:事件处理" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(7) "idreamo" ["tagsname"]=> string(40) "C语言|数据结构|队列|事件处理" ["tagsid"]=> string(23) "["246","247","248",395]" ["catesname"]=> string(12) "数据结构" ["catesid"]=> string(7) "["133"]" ["createtime"]=> string(10) "1511397279" ["_id"]=> string(3) "420" } [9]=> array(10) { ["id"]=> string(3) "419" ["text"]=> string(47) "久等了,博客园官方Android客户端发布" ["intro"]=> string(288) "目录 ECharts 异步加载 ECharts 数据可视化在过去几年中取得了巨大进展。开发人员对可视化产品的期望不再是简单的图表创建工具,而是在交互、性能、数据处理等方面有更高的要求。 chart.setOption({ color: [ " ["username"]=> string(3) "cmt" ["tagsname"]=> string(0) "" ["tagsid"]=> string(2) "[]" ["catesname"]=> string(0) "" ["catesid"]=> string(2) "[]" ["createtime"]=> string(10) "1511396549" ["_id"]=> string(3) "419" } } ["count"]=> int(200) } 222 java 枚举类型分析 - 爱码网

最近做android开发,需要用到枚举值,这样可以连续赋值,我按之前c++那样书写,如下所示:

public enum ColorSelect {
           RED_BAGE = 0,
           GREEN_BAGE,
           BLUE_BAGE;
    }

编译不过。

我将赋值语句修改了以后,如下所示:

public enum ColorSelect {
           RED_BAGE ,
           GREEN_BAGE,
           BLUE_BAGE;
    }

编译通过。说明C++那样的赋值方法不适用java。所以,我需要弄清楚的是:

1. 在java平台上,如何初始化枚举值。

2.像上述那样的枚举类型ColorSelect,没有赋值,为什么switch(ColorSelect) 可以运行?它是通过字符串还是整数值来匹配枚举类型。

为了弄清楚上述问题,我自己就写了个示范程序,将该程序编译后,看看结果,是否可以找到答案。

 

 

一. 如何初始化枚举值

下面是我的示范程序:

自己定义的枚举类:

public enum ColorSelect {   //定义枚举类ColorSelect
           RED_BAGE ,   //定义三个枚举对象
           GREEN_BAGE,
           BLUE_BAGE;
    }

通过反编译,这段代码反编译后的程序是:

public final class ColorSelect extends Enum
    {

        public static ColorSelect valueOf(String s)  //公有函数,该方法通过字符串获取对应的ColorSelect 对象
        {
            return (ColorSelect)Enum.valueOf(test/Enum/TestEnum$ColorSelect, s);
        }

        public static ColorSelect[] values()  //公有函数该方法获取所有的ColorSelect对象
        {
            ColorSelect acolorselect[] = ENUM$VALUES; //ENUM$VALUES是ColorSelect数组,下面的代码会将其进行初始化
            int i = acolorselect.length;
            ColorSelect acolorselect1[] = new ColorSelect[i];
            System.arraycopy(acolorselect, 0, acolorselect1, 0, i);
            return acolorselect1;
        }

        public static final ColorSelect BLUE_BAGE; // 定义公共成员BLUE_BAGE,属于ColorSelect对象
        private static final ColorSelect ENUM$VALUES[]; //定义私有成员ENUM$VALUES[],属于ColorSelect数组
        public static final ColorSelect GREEN_BAGE; // 定义公共成员GREEN_BAGE,属于ColorSelect对象
        public static final ColorSelect RED_BAGE;  // 定义公共成员RED_BAGE,属于ColorSelect对象
         static
        {//static里面这段代码,将上面定义的是三个公共成员ColorSelect对象进行初始化,然后将他们全部赋值给ENUM$VALUES
            RED_BAGE = new ColorSelect("RED_BAGE", 0);  //初始化BLUE_BAGE
            GREEN_BAGE = new ColorSelect("GREEN_BAGE", 1);  //初始化GREEN_BAGE
            BLUE_BAGE = new ColorSelect("BLUE_BAGE", 2); //初始化BLUE_BAGE
            ColorSelect acolorselect[] = new ColorSelect[3];
            ColorSelect colorselect = RED_BAGE;
            acolorselect[0] = colorselect;
            ColorSelect colorselect1 = GREEN_BAGE;
            acolorselect[1] = colorselect1;
            ColorSelect colorselect2 = BLUE_BAGE;
            acolorselect[2] = colorselect2;
            ENUM$VALUES = acolorselect;
        }

        private ColorSelect(String s, int i) //私有函数,调用父类进行初始化ColorSelect对象
        {
            super(s, i);
        }
    }

从该反编译的代码看,有两个公有成员函数:

 


public static ColorSelect valueOf(String s);  该方法通过字符串获取对应的ColorSelect 对象
public static ColorSelect[] values();  该方法获取所有的ColorSelect 对象
这两种方法,在java里面可以直接调用。

下面的是ColorSelect的数据成员。 

        public static final ColorSelect BLUE_BAGE;
        private static final ColorSelect ENUM$VALUES[];
        public static final ColorSelect GREEN_BAGE;
        public static final ColorSelect RED_BAGE;

公有数据就是BLUE_BAGE,GREEN_BAGE,RED_BAGE,它们本身属性就是ColorSelect类。所以,从这里可以看到枚举类定义的成员变量也是类。后续的代码:

            RED_BAGE = new ColorSelect("RED_BAGE", 0);
            GREEN_BAGE = new ColorSelect("GREEN_BAGE", 1);
            BLUE_BAGE = new ColorSelect("BLUE_BAGE", 2);

这三行相当于初始化这三个类,并且每个类分配唯一的序号,按定义时的顺序从0递增。我们在java代码,可以调用ColorSelect.BLUE_BAGE.ordinal()来得到对应的序号值。

 

通过以上分析,java枚举是一个类,不是语言本身实现的,而是编译器实现的,我们可以直接调用里面的方法。Enum 本身就是个普通的 class, 可以有很多自定义方法用来实现不同的功能。如果我们不自定义里面的方法,编译器就能初始化,默认顺序从0递增。我们也可以自定义方法,这样就能随便赋值。

下面是我们自定义的java枚举类型,可以赋值。

<span style="font-weight: normal;">  public enum Temp {
        /*通过括号赋值,而且必须有带参构造器和一属性跟方法,否则编译出错
         * 赋值必须是都赋值或都不赋值,不能一部分赋值一部分不赋值
         * 如果不赋值则不能写构造器,赋值编译也出错*/
        absoluteZero(-459), freezing(32),boiling(212), paperBurns(451);
        
        private final int value;
        public int getValue() {
            return value;
        }
        //构造器默认也只能是private, 从而保证构造函数只能在内部使用
        Temp(int value) {
            this.value = value;
        }
    }</span>

这就是一个枚举类,自定义方法来赋值。java不像C++那样简便,初始第一个值,后续值递增。赋值必须是都赋值或都不赋值,不能一部分赋值一部分不赋值。如果不赋值则不能写构造器,赋值编译也出错。

  Temp temp = null;
        Log.i("Temp##",temp.freezing.getValue()+""); 

在主函数中,我们调用temp.freezing.getValue(),得到对应的值32。

如果大家感觉自定义枚举类麻烦,其实也可以用别的方法来代替自定义枚举类。如下所示:

    public class ColorSelect {
         private static final int  RED_BAGE = 1;
         private static final int  GREEN_BAGE = 3;
         private static final int  BLUE_BAGE = 5;
    }

这种方法也比较方便。

二. 第一个疑问搞清楚了,我们现在要解决第二个问题。Switch到底通过字符串,还是整型来分辨枚举变量。

下面是java代码段:

   ColorSelect test = ColorSelect.BLUE_BAGE;
  
        switch(test){
        case RED_BAGE:
            Log.i("TEST####1","a");
            break;
        case GREEN_BAGE:
            Log.i("TEST####2","b");
            break;
        case BLUE_BAGE:
            Log.i("TEST####3","c");
            break;
            default:
            Log.i("TEST####4","d");
        }
   
       Log.i("TEST####ret", "e");

反编译后的代码:

{  //主函数
 ColorSelect colorselect = ColorSelect.BLUE_BAGE;
        ai = $SWITCH_TABLE$test$Enum$TestEnum$ColorSelect();  //调用子函数$SWITCH_TABLE$test$Enum$TestEnum$ColorSelect(),返回数组赋值给ai
        i = colorselect.ordinal();  //得到该枚举类型BLUE_BAGE的序号
        ai[i]; //switch根据ai[i]值来进行判断
        JVM INSTR tableswitch 1 3: default 56 // 1 3是ai[i]的取值范围
    //                   1 73
    //                   2 84
    //                   3 95;
           goto _L1 _L2 _L3 _L4
_L1:
        Log.i("TEST####4", "d");
_L6:
        Log.i("TEST####ret", "e");
        return;
_L2:
        Log.i("TEST####1", "a");
        continue; /* Loop/switch isn't completed */
_L3:
        Log.i("TEST####2", "b");
        continue; /* Loop/switch isn't completed */
_L4:
        Log.i("TEST####3", "c");
        if(true) goto _L6; else goto _L5
_L5:
    }

    private static int $SWITCH_TABLE$test$Enum$TestEnum$ColorSelect[];
}

//子函数
 static int[] $SWITCH_TABLE$test$Enum$TestEnum$ColorSelect()  //
    {
        int ai[] = $SWITCH_TABLE$test$Enum$TestEnum$ColorSelect;
        if(ai == null)
        {
            ai = new int[ColorSelect.values().length];  
            try  //下面的代码,将每一个枚举类型的序号值作为数组ai的下标,然后赋一个整数值
            {
                int i = ColorSelect.BLUE_BAGE.ordinal();  
                ai[i] = 3;
            }
            catch(NoSuchFieldError nosuchfielderror2) { }
            try
            {
                int j = ColorSelect.GREEN_BAGE.ordinal();
                ai[j] = 2;
            }
            catch(NoSuchFieldError nosuchfielderror1) { }
            try
            {
                int k = ColorSelect.RED_BAGE.ordinal();
                ai[k] = 1;
            }
            catch(NoSuchFieldError nosuchfielderror) { }
            $SWITCH_TABLE$test$Enum$TestEnum$ColorSelect = ai;
        }
        return ai;
    }

子函数$SWITCH_TABLE$test$Enum$TestEnum$ColorSelect()的功能:

通过int i = ColorSelect.BLUE_BAGE.ordinal()得到该类的唯一序号,作为数组下标,并且赋值给ai[i]。这样,每一个枚举类对应都有唯一的整数对应。然后返回数组ai[]。这个功能是编译器实现的。我感觉,子函数的功能有些多余,其实可以直接用之前初始化枚举类的时候的下标号,直接作为标识符也行,就不用再给每个枚举类重新赋整数值。

主函数里面,调用子函数$SWITCH_TABLE$test$Enum$TestEnum$ColorSelect(),switch()里面的参数是ai[i],根据这个整数值来判断分支。Java里面枚举值通过编译器给每个枚举类型赋整型数值,然后Switch通过识别这些整数来进行判断分支,这就解决了第二个疑问。
同时我们通过对比switch的java代码和反编译的代码,可以得到大概下面的结论。
1.每个标志位的"continue"说明该分支break。
2.最后一个分支的标志是if (true) goto _Lx,else goto _x。

同时我们通过对比switch的java代码和反编译的代码,可以得到大概下面的结论。
1.每个标志位的"continue"说明该分支break。
2.最后一个分支的标志是if (true) goto _Lx,else goto _x。

同时,还有些疑问,没弄明白?

我写了好几个switch的例子,反编译出来的代码有一个共同规律。

反编译代码1:

  JVM INSTR tableswitch 1 3: default 56
    //                   1 73
    //                   2 84
    //                   3 95;
           goto _L1 _L2 _L3 _L4

反编译代码2:

JVM INSTR tableswitch 0 2: default 60
    //                   0 77
    //                   1 88
    //                   2 99;
           goto _L1 _L2 _L3 _L4

这两个,标明 1, 2,3相互之间数值都相差11。第二个也是。这个搞不懂?同时,这些数值代表什么?

如果以上哪些不对的地方,请大家指正。

<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>
<pre></pre>

 

(转自:http://blog.csdn.net/bage1988320/article/details/6690845)

相关文章: