美文网首页
浅析Enum的原理

浅析Enum的原理

作者: hdychi | 来源:发表于2018-07-20 17:31 被阅读0次

一、用作示例的枚举类

package com.meituan.huangdanyang;

public enum Operator {

    ADD ("+") {
        @Override
        public int calculate(int a, int b) {
            return a + b;
        }
    },
    SUBTRACT ("-") {
        @Override
        public int calculate(int a, int b) {
            return a - b;
        }
    },
    MULTIPLY  ("*") {
        @Override
        public int calculate(int a, int b) {
            return a * b;
        }
    },
    DIVIDE ("/") {
        @Override
        public int calculate(int a, int b) {
            if (b == 0) {
                throw new IllegalArgumentException("divisor must not be 0");
            }
            return a / b;
        }
    };

    Operator (String operator) {
        this.operator = operator;
    }

    private String operator;
    public abstract int calculate(int a, int b);

    public String getOperator() {
        return operator;
    }

}

使用时,ADD ("+")其实就是调用了Operator的构造函数Operator (String operator) ,初始化一个operator为"+"的Operator对象而已,并重写了抽象方法calculate。

我们可以这样使用;

int res = Operator.ADD.calculate(1,2);
System.out.println(res);

二、反编译

运行之后,找到Operator.class文件,先用javap -c Operator.class看看:

Last login: Fri Jul 20 17:03:29 on ttys005
admindeMacBook-Pro:huangdanyang hdychi$ javap -classpath . -c Operator.class
Compiled from "Operator.java"
public abstract class com.meituan.huangdanyang.Operator extends java.lang.Enum<com.meituan.huangdanyang.Operator> {
  public static final com.meituan.huangdanyang.Operator ADD;

  public static final com.meituan.huangdanyang.Operator SUBTRACT;

  public static final com.meituan.huangdanyang.Operator MULTIPLY;

  public static final com.meituan.huangdanyang.Operator DIVIDE;

  public static com.meituan.huangdanyang.Operator[] values();
    Code:
       0: getstatic     #2                  // Field $VALUES:[Lcom/meituan/huangdanyang/Operator;
       3: invokevirtual #3                  // Method "[Lcom/meituan/huangdanyang/Operator;".clone:()Ljava/lang/Object;
       6: checkcast     #4                  // class "[Lcom/meituan/huangdanyang/Operator;"
       9: areturn

  public static com.meituan.huangdanyang.Operator valueOf(java.lang.String);
    Code:
       0: ldc           #5                  // class com/meituan/huangdanyang/Operator
       2: aload_0
       3: invokestatic  #6                  // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
       6: checkcast     #5                  // class com/meituan/huangdanyang/Operator
       9: areturn

  public abstract int calculate(int, int);

  public java.lang.String getOperator();
    Code:
       0: aload_0
       1: getfield      #8                  // Field operator:Ljava/lang/String;
       4: areturn

  com.meituan.huangdanyang.Operator(java.lang.String, int, java.lang.String, com.meituan.huangdanyang.Operator$1);
    Code:
       0: aload_0
       1: aload_1
       2: iload_2
       3: aload_3
       4: invokespecial #1                  // Method "<init>":(Ljava/lang/String;ILjava/lang/String;)V
       7: return

  static {};
    Code:
       0: new           #9                  // class com/meituan/huangdanyang/Operator$1
       3: dup
       4: ldc           #10                 // String ADD
       6: iconst_0
       7: ldc           #11                 // String +
       9: invokespecial #12                 // Method com/meituan/huangdanyang/Operator$1."<init>":(Ljava/lang/String;ILjava/lang/String;)V
      12: putstatic     #13                 // Field ADD:Lcom/meituan/huangdanyang/Operator;
      15: new           #14                 // class com/meituan/huangdanyang/Operator$2
      18: dup
      19: ldc           #15                 // String SUBTRACT
      21: iconst_1
      22: ldc           #16                 // String -
      24: invokespecial #17                 // Method com/meituan/huangdanyang/Operator$2."<init>":(Ljava/lang/String;ILjava/lang/String;)V
      27: putstatic     #18                 // Field SUBTRACT:Lcom/meituan/huangdanyang/Operator;
      30: new           #19                 // class com/meituan/huangdanyang/Operator$3
      33: dup
      34: ldc           #20                 // String MULTIPLY
      36: iconst_2
      37: ldc           #21                 // String *
      39: invokespecial #22                 // Method com/meituan/huangdanyang/Operator$3."<init>":(Ljava/lang/String;ILjava/lang/String;)V
      42: putstatic     #23                 // Field MULTIPLY:Lcom/meituan/huangdanyang/Operator;
      45: new           #24                 // class com/meituan/huangdanyang/Operator$4
      48: dup
      49: ldc           #25                 // String DIVIDE
      51: iconst_3
      52: ldc           #26                 // String /
      54: invokespecial #27                 // Method com/meituan/huangdanyang/Operator$4."<init>":(Ljava/lang/String;ILjava/lang/String;)V
      57: putstatic     #28                 // Field DIVIDE:Lcom/meituan/huangdanyang/Operator;
      60: iconst_4
      61: anewarray     #5                  // class com/meituan/huangdanyang/Operator
      64: dup
      65: iconst_0
      66: getstatic     #13                 // Field ADD:Lcom/meituan/huangdanyang/Operator;
      69: aastore
      70: dup
      71: iconst_1
      72: getstatic     #18                 // Field SUBTRACT:Lcom/meituan/huangdanyang/Operator;
      75: aastore
      76: dup
      77: iconst_2
      78: getstatic     #23                 // Field MULTIPLY:Lcom/meituan/huangdanyang/Operator;
      81: aastore
      82: dup
      83: iconst_3
      84: getstatic     #28                 // Field DIVIDE:Lcom/meituan/huangdanyang/Operator;
      87: aastore
      88: putstatic     #2                  // Field $VALUES:[Lcom/meituan/huangdanyang/Operator;
      91: return
}

笔者太菜了,看不懂。

底层群员.jpeg

还是来用一个好使的工具,jad,来把class文件反编译成一个java文件。

http://www.javadecompilers.com/jad

然后,./jad -sjava Operator.class

在当前命令行所在目录生成了Operator.java文件

Operator.java:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   Operator.java

package com.meituan.huangdanyang;

public abstract class Operator extends Enum
{

    public static Operator[] values()
    {
        return (Operator[])$VALUES.clone();
    }

    public static Operator valueOf(String name)
    {
        return (Operator)Enum.valueOf(com/meituan/huangdanyang/Operator, name);
    }

    private Operator(String s, int i, String operator)
    {
        super(s, i);
        this.operator = operator;
    }

    public abstract int calculate(int i, int j);

    public String getOperator()
    {
        return operator;
    }

    public static final Operator ADD;
    public static final Operator SUBTRACT;
    public static final Operator MULTIPLY;
    public static final Operator DIVIDE;
    private String operator;
    private static final Operator $VALUES[];

    static 
    {
        ADD = new Operator("ADD", 0, "+") {

            public int calculate(int a, int b)
            {
                return a + b;
            }

        }
;
        SUBTRACT = new Operator("SUBTRACT", 1, "-") {

            public int calculate(int a, int b)
            {
                return a - b;
            }

        }
;
        MULTIPLY = new Operator("MULTIPLY", 2, "*") {

            public int calculate(int a, int b)
            {
                return a * b;
            }

        }
;
        DIVIDE = new Operator("DIVIDE", 3, "/") {

            public int calculate(int a, int b)
            {
                if(b == 0)
                    throw new IllegalArgumentException("divisor must not be 0");
                else
                    return a / b;
            }

        }
;
        $VALUES = (new Operator[] {
            ADD, SUBTRACT, MULTIPLY, DIVIDE
        });
    }
}

可以看到,ADD、SUBSTRACT这四个,被编译成静态Operator对象,并且在静态区添加了代码,使用了内部类的方法,对四个常量进行了初始化。由于使用了内部类,在编译时还会产生Operator1.class,Operator2.class,Operator3.class,Operator4.class。

再次利用jad,反编译处java文件,打开:

// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3) 
// Source File Name:   Operator.java

package com.meituan.huangdanyang;


// Referenced classes of package com.meituan.huangdanyang:
//            Operator

static class Operator$1 extends Operator
{

    public int calculate(int a, int b)
    {
        return a + b;
    }

    Operator$1(String s, int i, String operator)
    {
        super(s, i, operator, null);
    }
}

就是一个静态内部类,实现了calculate方法。

同时为了满足Enum类都具有的values方法和valueOf方法,编译的时候,添加了一个$VALUES Operator数组,把枚举里的元素存入这个数组中,在调用values方法时就可以clone这个枚举里的元素。

相关文章

网友评论

      本文标题:浅析Enum的原理

      本文链接:https://www.haomeiwen.com/subject/jnpqmftx.html