# 发现类成员 > 原文: [https://docs.oracle.com/javase/tutorial/reflect/class/classMembers.html](https://docs.oracle.com/javase/tutorial/reflect/class/classMembers.html) [`Class`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html) 中提供了两类方法,用于访问字段,方法和构造器:枚举这些成员的方法和搜索特定成员的方法。还有一些不同的方法可以访问直接在类上声明的成员,而不是用于搜索继承成员的超接口和超类的方法。下表提供了所有成员定位方法及其特征的摘要。 Class Methods for Locating Fields | [`Class`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html) API | 成员名单? | 继承成员? | 私人成员? | | --- | --- | --- | --- | | [`getDeclaredField()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredField-java.lang.String-) | 没有 | 没有 | 是 | | [`getField()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getField-java.lang.String-) | 没有 | 是 | 没有 | | [`getDeclaredFields()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredFields--) | 是 | 没有 | 是 | | [`getFields()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getFields--) | 是 | 是 | 没有 | Class Methods for Locating Methods | [`Class`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html) API | 成员名单? | 继承成员? | 私人成员? | | --- | --- | --- | --- | | [`getDeclaredMethod()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredMethod-java.lang.String-java.lang.Class...-) | 没有 | 没有 | 是 | | [`getMethod()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getMethod-java.lang.String-java.lang.Class...-) | 没有 | 是 | 没有 | | [`getDeclaredMethods()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredMethods--) | 是 | 没有 | 是 | | [`getMethods()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getMethods--) | 是 | 是 | 没有 | Class Methods for Locating Constructors | [`Class`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html) API | 成员名单? | 继承成员? | 私人成员? | | --- | --- | --- | --- | | [`getDeclaredConstructor()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredConstructor-java.lang.Class...-) | 没有 | N / A <sup>1</sup> | 是 | | [`getConstructor()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getConstructor-java.lang.Class...-) | 没有 | N / A <sup>1</sup> | 没有 | | [`getDeclaredConstructors()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getDeclaredConstructors--) | 是 | N / A <sup>1</sup> | 是 | | [`getConstructors()`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getConstructors--) | 是 | N / A <sup>1</sup> | 没有 | <sup>1</sup> 构造器不是继承的。 给定一个类名并指示哪些成员感兴趣, [``ClassSpy``](example/ClassSpy.java)示例使用`get*s()`方法确定所有公共元素的列表,包括任何公共元素遗传。 ``` import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Member; import static java.lang.System.out; enum ClassMember { CONSTRUCTOR, FIELD, METHOD, CLASS, ALL } public class ClassSpy { public static void main(String... args) { try { Class c = Class.forName(args[0]); out.format("Class:%n %s%n%n", c.getCanonicalName()); Package p = c.getPackage(); out.format("Package:%n %s%n%n", (p != null ? p.getName() : "-- No Package --")); for (int i = 1; i < args.length; i++) { switch (ClassMember.valueOf(args[i])) { case CONSTRUCTOR: printMembers(c.getConstructors(), "Constructor"); break; case FIELD: printMembers(c.getFields(), "Fields"); break; case METHOD: printMembers(c.getMethods(), "Methods"); break; case CLASS: printClasses(c); break; case ALL: printMembers(c.getConstructors(), "Constuctors"); printMembers(c.getFields(), "Fields"); printMembers(c.getMethods(), "Methods"); printClasses(c); break; default: assert false; } } // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } private static void printMembers(Member[] mbrs, String s) { out.format("%s:%n", s); for (Member mbr : mbrs) { if (mbr instanceof Field) out.format(" %s%n", ((Field)mbr).toGenericString()); else if (mbr instanceof Constructor) out.format(" %s%n", ((Constructor)mbr).toGenericString()); else if (mbr instanceof Method) out.format(" %s%n", ((Method)mbr).toGenericString()); } if (mbrs.length == 0) out.format(" -- No %s --%n", s); out.format("%n"); } private static void printClasses(Class c) { out.format("Classes:%n"); Class[] clss = c.getClasses(); for (Class cls : clss) out.format(" %s%n", cls.getCanonicalName()); if (clss.length == 0) out.format(" -- No member interfaces, classes, or enums --%n"); out.format("%n"); } } ``` 这个例子比较紧凑;然而,由于 [`java.lang.reflect.Member`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Member.html) 接口自最早的反射实现以来已经存在,因此`printMembers()`方法略显尴尬,并且当泛型时它无法修改为包含更有用的`getGenericString()`方法介绍了。唯一的选择是如图所示进行测试和铸造,用`printConstructors()`,`printFields()`和`printMethods()`代替该方法,或者对 [`Member.getName()`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Member.html#getName--) 的相对备用结果感到满意。 输出样本及其解释如下。用户输入以斜体显示。 ``` $ java ClassSpy java.lang.ClassCastException CONSTRUCTOR Class: java.lang.ClassCastException Package: java.lang Constructor: public java.lang.ClassCastException() public java.lang.ClassCastException(java.lang.String) ``` 由于构造器不是继承的,因此找不到在超级类 [`RuntimeException`](https://docs.oracle.com/javase/8/docs/api/java/lang/RuntimeException.html) 和其他超类中定义的异常链机制构造器(具有 [`Throwable`](https://docs.oracle.com/javase/8/docs/api/java/lang/Throwable.html) 参数的构造器)) 。 ``` $ java ClassSpy java.nio.channels.ReadableByteChannel METHOD Class: java.nio.channels.ReadableByteChannel Package: java.nio.channels Methods: public abstract int java.nio.channels.ReadableByteChannel.read (java.nio.ByteBuffer) throws java.io.IOException public abstract void java.nio.channels.Channel.close() throws java.io.IOException public abstract boolean java.nio.channels.Channel.isOpen() ``` 接口 [`java.nio.channels.ReadableByteChannel`](https://docs.oracle.com/javase/8/docs/api/java/nio/channels/ReadableByteChannel.html) 定义 [`read()`](https://docs.oracle.com/javase/8/docs/api/java/nio/channels/ReadableByteChannel.html#read-java.nio.ByteBuffer-) 。其余方法继承自超级接口。通过将`get*s()`替换为`getDeclared*s()`,可以很容易地修改此代码以仅列出实际在类中声明的那些方法。 ``` $ java ClassSpy ClassMember FIELD METHOD Class: ClassMember Package: -- No Package -- Fields: public static final ClassMember ClassMember.CONSTRUCTOR public static final ClassMember ClassMember.FIELD public static final ClassMember ClassMember.METHOD public static final ClassMember ClassMember.CLASS public static final ClassMember ClassMember.ALL Methods: public static ClassMember ClassMember.valueOf(java.lang.String) public static ClassMember[] ClassMember.values() public final int java.lang.Enum.hashCode() public final int java.lang.Enum.compareTo(E) public int java.lang.Enum.compareTo(java.lang.Object) public final java.lang.String java.lang.Enum.name() public final boolean java.lang.Enum.equals(java.lang.Object) public java.lang.String java.lang.Enum.toString() public static T java.lang.Enum.valueOf (java.lang.Class,java.lang.String) public final java.lang.Class java.lang.Enum.getDeclaringClass() public final int java.lang.Enum.ordinal() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final void java.lang.Object.wait() hrows java.lang.InterruptedException public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll() ``` 在这些结果的字段部分中,列出了枚举常量。虽然这些是技术字段,但将它们与其他字段区分开来可能是有用的。为了这个目的,可以修改此示例以使用 [`java.lang.reflect.Field.isEnumConstant()`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Field.html#isEnumConstant--) 。 [``EnumSpy`` ](../special/example/EnumSpy.java)示例在该踪迹的后续部分[检查枚举](../special/enumMembers.html)中包含了一种可能的实现方式。 在输出的方法部分中,观察方法名称包含声明类的名称。因此,`toString()`方法由 [`Enum`](https://docs.oracle.com/javase/8/docs/api/java/lang/Enum.html#toString--) 实现,不是从 [`Object`](https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html) 遗传。可以通过使用 [`Field.getDeclaringClass()`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Field.html#getDeclaringClass--) 修改代码以使其更加明显。以下片段说明了潜在解决方案的一部分。 ``` if (mbr instanceof Field) { Field f = (Field)mbr; out.format(" %s%n", f.toGenericString()); out.format(" -- declared in: %s%n", f.getDeclaringClass()); } ```