专栏首页代码拾遗​反射基础之Enum

​反射基础之Enum

检查枚举

检查枚举主要由三个API:

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

示例如下:

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

运行结果:

$ 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获取其他信息:

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 ]" : "");
    }
}

运行结果:

$ 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)
根据枚举类型设置字段

示例:

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

运行结果:

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

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

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

运行结果:

$ 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)

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

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

运行:

$ 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)

本文分享自微信公众号 - 代码拾遗(gh_8f61e8bcb1b1)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2018-05-10

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 反射基础之Constructor

    构造器的声明包含了:名字,修饰符,参数和异常。可以通过java.lang.reflect.Constructor类获取这些信息。 下面的例子描述了如何获取构造器...

    代码拾遗
  • 反射基础之Field

    java.lang.reflect.Field 类的方法可以查询字段的信息。比如:名字,类型,修饰符和注解。同样也有方法可以动态访问和修改字段的值。

    代码拾遗
  • 反射基础之Method

    一个方法声明包括:方法名,描述符,参数,返回类型和异常。可以通过java.lang.reflect.Method类获取这些信息。 下面的例子说明了如何获取一个类...

    代码拾遗
  • 常见的 Java 错误及避免方法之第五集(每集10个错误后续持续发布)

    当输入期间意外终止文件或流时,将抛出“EOFException”。 以下是抛出EOFException异常的一个示例,来自JavaBeat应用程序:

    用户1289394
  • 学java就两个问题

    三哥
  • 为什么java越来越强势?

    目前很多的从业都有这种感觉,突然觉得c/c++就业机会以及升职的空间比java的差距越来越大了,有人就宣称java是目前国内就业最好的语言,说的有点夸张但是ja...

    程序员互动联盟
  • Jvm中各种内存溢出情况分析

    oom即OutOfMemoryError,出现这个报错的主要原因是内存空间不足以装下数据导致抛出异常。要探讨JVM出现oom的情况,首先要了解下jvm的内存模型...

    DH镔
  • java知识点归纳

    java新手知识点归纳-java基础部分 ? 一. Java的运行(基础必备) 这条可能出看很简单,java程序的运行谁不会呢?不过很多时候, 我们只是单纯通过...

    企鹅号小编
  • OkHttp's NullPointerException in HttpUrl.class

    今天测试在小米5.0-6.0的机型中测试发现一个空指针的异常,经过排查后发现OkHttp的请求参数不能为null,这个请求接口会上传当前机型的手机号、ip地址和...

    萬物並作吾以觀復
  • Java编程思想学习录(连载之:一切都是对象)

    CodeSheep

扫码关注云+社区

领取腾讯云代金券