A browser with JavaScript enabled is required for this page to operate properly.
Documentation

The Java™ Tutorials
Trail: The Reflection API
Lesson: Classes
« PreviousTrailNext »

The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available.
See Dev.java for updated tutorials taking advantage of the latest releases.
See Java Language Changes for a summary of updated language features in Java SE 9 and subsequent releases.
See JDK Release Notes for information about new features, enhancements, and removed or deprecated options for all JDK releases.

Discovering Class Members

There are two categories of methods provided in Class for accessing fields, methods, and constructors: methods which enumerate these members and methods which search for particular members. Also there are distinct methods for accessing members declared directly on the class versus methods which search the superinterfaces and superclasses for inherited members. The following tables provide a summary of all the member-locating methods and their characteristics.


Class Methods for Locating Fields
Class API List of members? Inherited members? Private members?
getDeclaredField() no no yes
getField() no yes no
getDeclaredFields() yes no yes
getFields() yes yes no


Class Methods for Locating Methods
Class API List of members? Inherited members? Private members?
getDeclaredMethod() no no yes
getMethod() no yes no
getDeclaredMethods() yes no yes
getMethods() yes yes no


Class Methods for Locating Constructors
Class API List of members? Inherited members? Private members?
getDeclaredConstructor() no N/A1 yes
getConstructor() no N/A1 no
getDeclaredConstructors() yes N/A1 yes
getConstructors() yes N/A1 no

1 Constructors are not inherited.

Given a class name and an indication of which members are of interest, the ClassSpy example uses the get*s() methods to determine the list of all public elements, including any which are inherited.

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

This example is relatively compact; however the printMembers() method is slightly awkward due to the fact that the java.lang.reflect.Member interface has existed since the earliest implementations of reflection and it could not be modified to include the more useful getGenericString() method when generics were introduced. The only alternatives are to test and cast as shown, replace this method with printConstructors(), printFields(), and printMethods(), or to be satisfied with the relatively spare results of Member.getName().

Samples of the output and their interpretation follows. User input is in italics.

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

Since constructors are not inherited, the exception chaining mechanism constructors (those with a Throwable parameter) which are defined in the immediate super class RuntimeException and other super classes are not found.

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

The interface java.nio.channels.ReadableByteChannel defines read(). The remaining methods are inherited from a super interface. This code could easily be modified to list only those methods that are actually declared in the class by replacing get*s() with 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> T java.lang.Enum.valueOf
 (java.lang.Class<T>,java.lang.String)
 public final java.lang.Class<E> 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()

In the fields portion of these results, enum constants are listed. While these are technically fields, it might be useful to distinguish them from other fields. This example could be modified to use java.lang.reflect.Field.isEnumConstant() for this purpose. The EnumSpy example in a later section of this trail, Examining Enums, contains a possible implementation.

In the methods section of the output, observe that the method name includes the name of the declaring class. Thus, the toString() method is implemented by Enum, not inherited from Object. The code could be amended to make this more obvious by using Field.getDeclaringClass(). The following fragment illustrates part of a potential solution.

if (mbr instanceof Field) {
 Field f = (Field)mbr;
 out.format(" %s%n", f.toGenericString());
 out.format(" -- declared in: %s%n", f.getDeclaringClass());
}
« PreviousTrailNext »

Previous page: Examining Class Modifiers and Types
Next page: Troubleshooting

AltStyle によって変換されたページ (->オリジナル) /