前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >​反射基础之Enum

​反射基础之Enum

作者头像
代码拾遗
发布2018-07-24 15:50:22
9270
发布2018-07-24 15:50:22
举报
文章被收录于专栏:代码拾遗代码拾遗
检查枚举

检查枚举主要由三个API:

  • Class.isEnum(): 判断类是否是一个枚举
  • Class.getEnumConstants(): 根据枚举中的声明顺序获取枚举常量
  • java.lang.reflect.Field.isEnumConstant() 判断字段是否是枚举

示例如下:

代码语言:javascript
复制
import java.util.Arrays;
import static java.lang.System.out;

enum Eon { HADEAN, ARCHAEAN, PROTEROZOIC, PHANEROZOIC }

public class EnumConstants {
    public static void main(String... args) {
    try {
        Class<?> c = (args.length == 0 ? Eon.class : Class.forName(args[0]));
        out.format("Enum name:  %s%nEnum constants:  %s%n",
               c.getName(), Arrays.asList(c.getEnumConstants()));
        if (c == Eon.class)
        out.format("  Eon.values():  %s%n",
               Arrays.asList(Eon.values()));

        // production code should handle this exception more gracefully
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    }
    }
}

运行结果:

代码语言:javascript
复制
$ java EnumConstants java.lang.annotation.RetentionPolicy
Enum name:  java.lang.annotation.RetentionPolicy
Enum constants:  [SOURCE, CLASS, RUNTIME]
$ java EnumConstants java.util.concurrent.TimeUnit
Enum name:  java.util.concurrent.TimeUnit
Enum constants:  [NANOSECONDS, MICROSECONDS, 
                  MILLISECONDS, SECONDS, 
                  MINUTES, HOURS, DAYS]

因为枚举也是一个类,所以也可以通过Field,Method,Constructor的反射API获取其他信息:

代码语言:javascript
复制
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Member;
import java.util.List;
import java.util.ArrayList;
import static java.lang.System.out;

public class EnumSpy {
    private static final String fmt = "  %11s:  %s %s%n";

    public static void main(String... args) {
    try {
        Class<?> c = Class.forName(args[0]);
        if (!c.isEnum()) {
        out.format("%s is not an enum type%n", c);
        return;
        }
        out.format("Class:  %s%n", c);

        Field[] flds = c.getDeclaredFields();
        List<Field> cst = new ArrayList<Field>();  // enum constants
        List<Field> mbr = new ArrayList<Field>();  // member fields
        for (Field f : flds) {
        if (f.isEnumConstant())
            cst.add(f);
        else
            mbr.add(f);
        }
        if (!cst.isEmpty())
        print(cst, "Constant");
        if (!mbr.isEmpty())
        print(mbr, "Field");

        Constructor[] ctors = c.getDeclaredConstructors();
        for (Constructor ctor : ctors) {
        out.format(fmt, "Constructor", ctor.toGenericString(),
               synthetic(ctor));
        }

        Method[] mths = c.getDeclaredMethods();
        for (Method m : mths) {
        out.format(fmt, "Method", m.toGenericString(),
               synthetic(m));
        }

        // production code should handle this exception more gracefully
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    }
    }

    private static void print(List<Field> lst, String s) {
    for (Field f : lst) {
         out.format(fmt, s, f.toGenericString(), synthetic(f));
    }
    }

    private static String synthetic(Member m) {
    return (m.isSynthetic() ? "[ synthetic ]" : "");
    }
}

运行结果:

代码语言:javascript
复制
$ java EnumSpy java.lang.annotation.RetentionPolicy
Class:  class java.lang.annotation.RetentionPolicy
     Constant:  public static final java.lang.annotation.RetentionPolicy
                  java.lang.annotation.RetentionPolicy.SOURCE 
     Constant:  public static final java.lang.annotation.RetentionPolicy
                  java.lang.annotation.RetentionPolicy.CLASS 
     Constant:  public static final java.lang.annotation.RetentionPolicy 
                  java.lang.annotation.RetentionPolicy.RUNTIME 
        Field:  private static final java.lang.annotation.RetentionPolicy[] 
                  java.lang.annotation.RetentionPolicy. [ synthetic ]
  Constructor:  private java.lang.annotation.RetentionPolicy() 
       Method:  public static java.lang.annotation.RetentionPolicy[]
                  java.lang.annotation.RetentionPolicy.values() 
       Method:  public static java.lang.annotation.RetentionPolicy
                  java.lang.annotation.RetentionPolicy.valueOf(java.lang.String)
根据枚举类型设置字段

示例:

代码语言:javascript
复制
Consider application which needs to dynamically modify the trace level in a server application which normally does not allow this change during runtime. Assume the instance of the server object is available. The SetTrace example shows how code can translate the String representation of an enum into an enum type and retrieve and set the value of a field storing an enum.
import java.lang.reflect.Field;
import static java.lang.System.out;

enum TraceLevel { OFF, LOW, MEDIUM, HIGH, DEBUG }

class MyServer {
    private TraceLevel level = TraceLevel.OFF;
}

public class SetTrace {
    public static void main(String... args) {
    TraceLevel newLevel = TraceLevel.valueOf(args[0]);

    try {
        MyServer svr = new MyServer();
        Class<?> c = svr.getClass();
        Field f = c.getDeclaredField("level");
        f.setAccessible(true);
        TraceLevel oldLevel = (TraceLevel)f.get(svr);
        out.format("Original trace level:  %s%n", oldLevel);

        if (oldLevel != newLevel) {
         f.set(svr, newLevel);
        out.format("    New  trace level:  %s%n", f.get(svr));
        }

        // production code should handle these exceptions more gracefully
    } catch (IllegalArgumentException x) {
        x.printStackTrace();
    } catch (IllegalAccessException x) {
        x.printStackTrace();
    } catch (NoSuchFieldException x) {
        x.printStackTrace();
    }
    }
}

运行结果:

代码语言:javascript
复制
$ java SetTrace OFF
Original trace level:  OFF
$ java SetTrace DEBUG
Original trace level:  OFF
    New  trace level:  DEBUG
问题排查
尝试初始化枚举类型或者对字段设置一个不兼容的枚举类型时抛出 IllegalArgumentException

示例:尝试初始化一个枚举类型

代码语言:javascript
复制
IllegalArgumentException When Attempting to Instantiate an Enum Type
As has been mentioned, instantiation of enum types is forbidden. The EnumTrouble example attempts this.
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import static java.lang.System.out;

enum Charge {
    POSITIVE, NEGATIVE, NEUTRAL;
    Charge() {
    out.format("under construction%n");
    }
}

public class EnumTrouble {

    public static void main(String... args) {
    try {
        Class<?> c = Charge.class;

         Constructor[] ctors = c.getDeclaredConstructors();
         for (Constructor ctor : ctors) {
        out.format("Constructor: %s%n",  ctor.toGenericString());
         ctor.setAccessible(true);
         ctor.newInstance();
         }

        // production code should handle these exceptions more gracefully
    } catch (InstantiationException x) {
        x.printStackTrace();
    } catch (IllegalAccessException x) {
        x.printStackTrace();
    } catch (InvocationTargetException x) {
        x.printStackTrace();
    }
    }
}

运行结果:

代码语言:javascript
复制
$ java EnumTrouble
Constructor: private Charge()
Exception in thread "main" java.lang.IllegalArgumentException: Cannot
  reflectively create enum objects
        at java.lang.reflect.Constructor.newInstance(Constructor.java:511)
        at EnumTrouble.main(EnumTrouble.java:22)

示例:设置不兼容的枚举类型

代码语言:javascript
复制
import java.lang.reflect.Field;

enum E0 { A, B }
enum E1 { A, B }

class ETest {
    private E0 fld = E0.A;
}

public class EnumTroubleToo {
    public static void main(String... args) {
    try {
        ETest test = new ETest();
        Field f = test.getClass().getDeclaredField("fld");
        f.setAccessible(true);
         f.set(test, E1.A);  // IllegalArgumentException

        // production code should handle these exceptions more gracefully
    } catch (NoSuchFieldException x) {
        x.printStackTrace();
    } catch (IllegalAccessException x) {
        x.printStackTrace();
    }
    }
}

运行:

代码语言:javascript
复制
$ java EnumTroubleToo
Exception in thread "main" java.lang.IllegalArgumentException: Can not set E0
  field ETest.fld to E1
        at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException
          (UnsafeFieldAccessorImpl.java:146)
        at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException
          (UnsafeFieldAccessorImpl.java:150)
        at sun.reflect.UnsafeObjectFieldAccessorImpl.set
          (UnsafeObjectFieldAccessorImpl.java:63)
        at java.lang.reflect.Field.set(Field.java:657)
        at EnumTroubleToo.main(EnumTroubleToo.java:16)
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-05-10,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 代码拾遗 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 检查枚举
  • 根据枚举类型设置字段
  • 问题排查
    • 尝试初始化枚举类型或者对字段设置一个不兼容的枚举类型时抛出 IllegalArgumentException
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档