文档

Java™教程
隐藏目录
检查枚举
路径: 反射API
课程: 数组和枚举类型
章节: 枚举类型

枚举类型的检查

反射提供了三个特定于枚举的API:

Class.isEnum()
表示该类是否代表一个枚举类型
Class.getEnumConstants()
检索按声明顺序定义的枚举常量列表
java.lang.reflect.Field.isEnumConstant()
表示该字段是否代表枚举类型的元素

有时需要动态检索枚举常量列表;在非反射代码中,可以通过调用枚举的隐式声明静态方法 values() 来实现。如果没有枚举类型的实例,则获取可能值列表的唯一方法是调用 Class.getEnumConstants(),因为无法实例化枚举类型。

给定一个完全限定名,EnumConstants 示例演示了如何使用 Class.getEnumConstants() 检索枚举中有序的常量列表。

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("枚举名称:%s%n枚举常量:%s%n",
		       c.getName(), Arrays.asList(c.getEnumConstants()));
	    if (c == Eon.class)
		out.format("  Eon.values():  %s%n",
			   Arrays.asList(Eon.values()));

        // 生产代码应更优雅地处理此异常
	} catch (ClassNotFoundException x) {
	    x.printStackTrace();
	}
    }
}

以下是输出的示例。用户输入以斜体显示。

$ java EnumConstants java.lang.annotation.RetentionPolicy
枚举名称:java.lang.annotation.RetentionPolicy
枚举常量:[SOURCE, CLASS, RUNTIME]
$ java EnumConstants java.util.concurrent.TimeUnit
枚举名称:java.util.concurrent.TimeUnit
枚举常量:[NANOSECONDS, MICROSECONDS, 
                  MILLISECONDS, SECONDS, 
                  MINUTES, HOURS, DAYS]

这个例子还展示了通过调用Class.getEnumConstants()返回的值与在枚举类型上调用values()返回的值是相同的。

$ java EnumConstants
枚举名称:  Eon
枚举常量:  [HADEAN, ARCHAEAN, 
                  PROTEROZOIC, PHANEROZOIC]
Eon.values():  [HADEAN, ARCHAEAN, 
                PROTEROZOIC, PHANEROZOIC]

由于枚举是类,因此可以使用相同的反射API获取其他信息,这些API在本教程的字段方法构造器部分中有详细描述。示例代码EnumSpy演示了如何使用这些API获取枚举声明的附加信息。示例使用Class.isEnum()来限制要检查的类集合。它还使用Field.isEnumConstant()来区分枚举常量和枚举声明中的其他字段(并非所有字段都是枚举常量)。

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 不是枚举类型%n", c);
		return;
	    }
	    out.format("类:  %s%n", c);

	    Field[] flds = c.getDeclaredFields();
	    List<Field> cst = new ArrayList<Field>();  // 枚举常量
	    List<Field> mbr = new ArrayList<Field>();  // 成员字段
	    for (Field f : flds) {
		if (f.isEnumConstant())
		    cst.add(f);
		else
		    mbr.add(f);
	    }
	    if (!cst.isEmpty())
		print(cst, "常量");
	    if (!mbr.isEmpty())
		print(mbr, "字段");

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

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

        // 产品代码应更优雅地处理此异常
	} 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() ? "[ 合成的 ]" : "");
    }
}
$ java EnumSpy java.lang.annotation.RetentionPolicy
类:  class java.lang.annotation.RetentionPolicy
     常量:  public static final java.lang.annotation.RetentionPolicy
                  java.lang.annotation.RetentionPolicy.SOURCE 
     常量:  public static final java.lang.annotation.RetentionPolicy
                  java.lang.annotation.RetentionPolicy.CLASS 
     常量:  public static final java.lang.annotation.RetentionPolicy 
                  java.lang.annotation.RetentionPolicy.RUNTIME 
        字段:  private static final java.lang.annotation.RetentionPolicy[] 
                  java.lang.annotation.RetentionPolicy. [ synthetic ]
  构造方法:  private java.lang.annotation.RetentionPolicy() 
       方法:  public static java.lang.annotation.RetentionPolicy[]
                  java.lang.annotation.RetentionPolicy.values() 
       方法:  public static java.lang.annotation.RetentionPolicy
                  java.lang.annotation.RetentionPolicy.valueOf(java.lang.String) 

输出显示了 java.lang.annotation.RetentionPolicy 的声明仅包含三个枚举常量。这些枚举常量被公开为 public static final 字段。字段、构造方法和方法是由编译器生成的。 $VALUES 字段与 values() 方法的实现有关。


注意: 由于各种原因,包括对枚举类型的演进支持,枚举常量的声明顺序很重要。 Class.getFields()Class.getDeclaredFields() 不保证返回的值的顺序与声明源代码中的顺序匹配。如果应用程序需要排序,请使用 Class.getEnumConstants()

输出结果中的 java.util.concurrent.TimeUnit 显示了更复杂的枚举类型的示例。该类包含多个方法,以及额外的声明为 static final 的字段,这些字段不是枚举常量。

$ java EnumSpy java.util.concurrent.TimeUnit
类:  class java.util.concurrent.TimeUnit
     常量:  public static final java.util.concurrent.TimeUnit
                  java.util.concurrent.TimeUnit.NANOSECONDS
     常量:  public static final java.util.concurrent.TimeUnit
                  java.util.concurrent.TimeUnit.MICROSECONDS
     常量:  public static final java.util.concurrent.TimeUnit
                  java.util.concurrent.TimeUnit.MILLISECONDS
     常量:  public static final java.util.concurrent.TimeUnit
                  java.util.concurrent.TimeUnit.SECONDS
     常量:  public static final java.util.concurrent.TimeUnit
                  java.util.concurrent.TimeUnit.MINUTES
     常量:  public static final java.util.concurrent.TimeUnit
                  java.util.concurrent.TimeUnit.HOURS
     常量:  public static final java.util.concurrent.TimeUnit
                  java.util.concurrent.TimeUnit.DAYS
        字段:  static final long java.util.concurrent.TimeUnit.C0
        字段:  static final long java.util.concurrent.TimeUnit.C1
        字段:  static final long java.util.concurrent.TimeUnit.C2
        字段:  static final long java.util.concurrent.TimeUnit.C3
        字段:  static final long java.util.concurrent.TimeUnit.C4
        字段:  static final long java.util.concurrent.TimeUnit.C5
        字段:  static final long java.util.concurrent.TimeUnit.C6
        字段:  static final long java.util.concurrent.TimeUnit.MAX
        字段:  private static final java.util.concurrent.TimeUnit[] 
                  java.util.concurrent.TimeUnit. [ synthetic ]
  构造方法:  private java.util.concurrent.TimeUnit()
  构造方法:  java.util.concurrent.TimeUnit
                  (java.lang.String,int,java.util.concurrent.TimeUnit)
                  [ synthetic ]
       方法:  public static java.util.concurrent.TimeUnit
                  java.util.concurrent.TimeUnit.valueOf(java.lang.String)
       方法:  public static java.util.concurrent.TimeUnit[] 
                  java.util.concurrent.TimeUnit.values()
       方法:  public void java.util.concurrent.TimeUnit.sleep(long) 
                  throws java.lang.InterruptedException
       方法:  public long java.util.concurrent.TimeUnit.toNanos(long)
       方法:  public long java.util.concurrent.TimeUnit.convert
                  (long,java.util.concurrent.TimeUnit)
       方法:  abstract int java.util.concurrent.TimeUnit.excessNanos
                  (long,long)
       方法:  public void java.util.concurrent.TimeUnit.timedJoin
                  (java.lang.Thread,long) throws java.lang.InterruptedException
       方法:  public void java.util.concurrent.TimeUnit.timedWait
                  (java.lang.Object,long) throws java.lang.InterruptedException
       方法:  public long java.util.concurrent.TimeUnit.toDays(long)
       方法:  public long java.util.concurrent.TimeUnit.toHours(long)
       方法:  public long java.util.concurrent.TimeUnit.toMicros(long)
       方法:  public long java.util.concurrent.TimeUnit.toMillis(long)
       方法:  public long java.util.concurrent.TimeUnit.toMinutes(long)
       方法:  public long java.util.concurrent.TimeUnit.toSeconds(long)
       方法:  static long java.util.concurrent.TimeUnit.x(long,long,long)

上一页: 枚举类型
下一页: 使用枚举类型获取和设置字段