Anda di halaman 1dari 95

Trail: The Reflection API

Uses of Reflection
Reflection is commonly used by programs which require the ability to examine or modify the runtime behavior of applications running in the Java virtual machine. This is a relatively advanced feature and should be used only by developers who have a strong grasp of the fundamentals of the language. With that caveat in mind, reflection is a powerful technique and can enable applications to perform operations which would otherwise be impossible. Extensibility Features An application may make use of external, user-defined classes by creating instances of extensibility objects using their fully-qualified names. Class Browsers and Visual Development Environments A class browser needs to be able to enumerate the members of classes. Visual development environments can benefit from making use of type information available in reflection to aid the developer in writing correct code. Debuggers and Test Tools Debuggers need to be able to examine private members on classes. Test harnesses can make use of reflection to systematically call a discoverable set APIs defined on a class, to insure a high level of code coverage in a test suite.

Drawbacks of Reflection
Reflection is powerful, but should not be used indiscriminately. If it is possible to perform an operation without using reflection, then it is preferable to avoid using it. The following concerns should be kept in mind when accessing code via reflection. Performance Overhead Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications. Security Restrictions Reflection requires a runtime permission which may not be present when running under a security manager. This is in an important consideration for code which has to run in a restricted security context, such as in an Applet. Exposure of Internals

Since reflection allows code to perform operations that would be illegal in non-reflective code, such as accessing private fields and methods, the use of reflection can result in unexpected side-effects, which may render code dysfunctional and may destroy portability. Reflective code breaks abstractions and therefore may change behavior with upgrades of the platform. Lesson: Classes Every object is either a reference or primitive type. Reference types all inherit from java.lang.Object. Classes, enums, arrays, and interfaces are all reference types. There is a fixed set of primitive types: boolean, byte, short, int, long, char, float, and double. Examples of reference types include java.lang.String, all of the wrapper classes for primitive types such as java.lang.Double, the interface java.io.Serializable, and the enum javax.swing.SortOrder. For every type of object, the Java virtual machine instantiates an immutable instance of java.lang.Class which provides methods to examine the runtime properties of the object including its members and type information. Class also provides the ability to create new classes and objects. Most importantly, it is the entry point for all of the Reflection APIs. This lesson covers the most commonly used reflection operations involving classes: Retrieving Class Objects describes the ways to get a Class Examining Class Modifiers and Types shows how to access the class declaration information Discovering Class Members illustrates how to list the constructors, fields, methods, and nested classes in a class Troubleshooting describes common errors encountered when using Class

Retrieving Class Objects The entry point for all reflection operations is java.lang.Class. With the exception of java.lang.reflect.ReflectPermission, none of the classes in java.lang.reflect have public constructors. To get to these classes, it is necessary to invoke appropriate methods on Class. There are several ways to get a Class depending on whether the code has access to an object, the name of class, a type, or an existing Class.

Object.getClass()

If an instance of an object is available, then the simplest way to get its Class is to invoke Object.getClass(). Of course, this only works for reference types which all inherit from Object. Some examples follow.
Class c = "foo".getClass();

Returns the Class for String


Class c = System.console().getClass();

There is a unique console associated with the virtual machine which is returned by the static method System.console(). The value returned by getClass() is the Class corresponding to java.io.Console.
enum E { A, B } Class c = A.getClass();

is is an instance of the enum E; thus getClass() returns the Class corresponding to the enumeration type E.
A byte[] bytes = new byte[1024]; Class c = bytes.getClass();

Since arrays are Objects, it is also possible to invoke getClass() on an instance of an array. The returned Class corresponds to an array with component type byte.
import java.util.HashSet; import java.util.Set; Set<String> s = new HashSet<String>(); Class c = s.getClass();

In this case, java.util.Set is an interface to an object of type java.util.HashSet. The value returned by getClass() is the class corresponding to java.util.HashSet.

The .class Syntax


If the type is available but there is no instance then it is possible to obtain a Class by appending ".class" to the name of the type. This is also the easiest way to obtain the Class for a primitive type.
boolean b; Class c = b.getClass(); Class c = boolean.class; // compile-time error // correct

Note that the statement boolean.getClass() would produce a compiletime error because a boolean is a primitive type and cannot be dereferenced. The .class syntax returns the Class corresponding to the type boolean.
Class c = java.io.PrintStream.class;

The variable c will be the Class corresponding to the type java.io.PrintStream.


Class c = int[][][].class;

The .class syntax may be used to retrieve a Class corresponding to a multi-dimensional array of a given type.

Class.forName()
If the fully-qualified name of a class is available, it is possible to get the corresponding Class using the static method Class.forName(). This cannot be used for primitive types. The syntax for names of array classes is described by Class.getName(). This syntax is applicable to references and primitive types.
Class c = Class.forName("com.duke.MyLocaleServiceProvider ");

This statement will create a class from the given fully-qualified name.
Class cDoubleArray = Class.forName("[D"); Class cStringArray = Class.forName("[[Ljava.lang.String;");

The variable cDoubleArray will contain the Class corresponding to an array of primitive type double (i.e. the same as double[].class). The cStringArray variable will contain the Class corresponding to a twodimensional array of String (i.e. identical to String[][].class).

TYPE Field for Primitive Type Wrappers


The .class syntax is a more convenient and the preferred way to obtain the Class for a primitive type; however there is another way to acquire the Class. Each of the primitive types and void has a wrapper class in java.lang that is used for boxing of primitive types to reference types. Each wrapper class contains a field named TYPE which is equal to the Class for the primitive type being wrapped.

Class c = Double.TYPE;

There is a class java.lang.Double which is used to wrap the primitive type double whenever an Object is required. The value of Double.TYPE is identical to that of double.class.
Class c = Void.TYPE; Void.TYPE

is identical to void.class.

Methods that Return Classes


There are several Reflection APIs which return classes but these may only be accessed if a Class has already been obtained either directly or indirectly.
Class.getSuperclass()

Returns the super class for the given class.


Class c = javax.swing.JButton.class.getSuperclass(); The super class of javax.swing.JButton is javax.swing.AbstractButton. Class.getClasses()

Returns all the public classes, interfaces, and enums that are members of the class including inherited members.
Class<?>[] c = Character.class.getClasses(); Character contains two member classes Character.Subset and Character.UnicodeBlock. Class.getDeclaredClasses()

Returns all of the classes interfaces, and enums that are explicitly declared in this class.
Class<?>[] c = Character.class.getDeclaredClasses(); Character contains two public member classes Character.Subset and Character.UnicodeBlock and one private class Character.CharacterCache. { Class, java.lang.reflect. { Field, Method, Constructor } }.getDeclaringClass() Returns the Class in which these members were declared. Anonymous

classes will not have a declaring class but will have an enclosing class.
import java.lang.reflect.Field; Field f = System.class.getField("out"); Class c = f.getDeclaringClass(); field out is declared in System. public class MyClass { static Object o = new Object() { public void m() {} };

The

static Class<c> = o.getClass().getEnclosingClass(); }

The declaring class of the anonymous class defined by o is null.


Class.getEnclosingClass()

Returns the immediately enclosing class of the class. The


Class c = Thread.State.class().getEnclosingClass(); enclosing class of the enum Thread.State is Thread. public class MyClass { static Object o = new Object() { public void m() {} }; static Class<c> = o.getClass().getEnclosingClass(); } anonymous class defined by o is enclosed by MyClass.

The

Examining Class Modifiers and Types A class may be declared with one or more modifiers which affect its runtime behavior:

Access modifiers: public, protected, and private Modifier requiring override: abstract Modifier restricting to one instance: static Modifier prohibiting value modification: final Modifier forcing strict floating point behavior: strictfp Annotations

Not all modifiers are allowed on all classes, for example an interface cannot be final and an enum cannot be abstract. java.lang.reflect.Modifier contains declarations for all possible modifiers. It also contains methods which may be used to decode the set of modifiers returned by Class.getModifiers(). The ClassDeclarationSpy example shows how to obtain the declaration components of a class including the modifiers, generic type parameters, implemented interfaces, and the inheritance path. Since Class implements the java.lang.reflect.AnnotatedElement interface it is also possible to query the runtime annotations.
import import import import import import import import java.lang.annotation.Annotation; java.lang.reflect.Modifier; java.lang.reflect.Type; java.lang.reflect.TypeVariable; java.util.Arrays; java.util.ArrayList; java.util.List; static java.lang.System.out;

public class ClassDeclarationSpy { public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); out.format("Class:%n %s%n%n", c.getCanonicalName()); out.format("Modifiers:%n %s%n%n", Modifier.toString(c.getModifiers())); out.format("Type Parameters:%n"); TypeVariable[] tv = c.getTypeParameters(); if (tv.length != 0) { out.format(" "); for (TypeVariable t : tv) out.format("%s ", t.getName()); out.format("%n%n"); } else { out.format(" -- No Type Parameters --%n%n"); } out.format("Implemented Interfaces:%n"); Type[] intfs = c.getGenericInterfaces(); if (intfs.length != 0) { for (Type intf : intfs) out.format(" %s%n", intf.toString()); out.format("%n"); } else { out.format(" -- No Implemented Interfaces --%n%n"); } out.format("Inheritance Path:%n"); List<Class> l = new ArrayList<Class>(); printAncestor(c, l); if (l.size() != 0) { for (Class<?> cl : l) out.format(" %s%n", cl.getCanonicalName()); out.format("%n"); } else { out.format(" -- No Super Classes -%n%n"); } out.format("Annotations:%n"); Annotation[] ann = c.getAnnotations(); if (ann.length != 0) { for (Annotation a : ann) out.format(" %s%n", a.toString()); out.format("%n"); } else {

%n"); }

out.format("

-- No Annotations --%n

// production code should handle this exception more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } private static void printAncestor(Class<?> c, List<Class> l) { Class<?> ancestor = c.getSuperclass(); if (ancestor != null) { l.add(ancestor); printAncestor(ancestor, l); } } }

A few samples of the output follows. User input is in italics.


$ java ClassDeclarationSpy java.util.concurrent.ConcurrentNavigableMap Class: java.util.concurrent.ConcurrentNavigableMap Modifiers: public abstract interface Type Parameters: K V Implemented Interfaces: java.util.concurrent.ConcurrentMap<K, V> java.util.NavigableMap<K, V> Inheritance Path: -- No Super Classes -Annotations: -- No Annotations --

This is the actual declaration for


java.util.concurrent.ConcurrentNavigableMap

in the source code:

public interface ConcurrentNavigableMap<K,V> extends ConcurrentMap, NavigableMap<K,V>

Note that since this is an interface, it is implicitly abstract. The compiler adds this modifier for every interface. Also, this declaration contains two generic type parameters, K and V. The example code simply prints the names of these parameters, but is it possible to retrieve additional 8

information about them using methods in java.lang.reflect.TypeVariable. Interfaces may also implement other interfaces as shown above.
$ java ClassDeclarationSpy "[Ljava.lang.String;" Class: java.lang.String[] Modifiers: public abstract final Type Parameters: -- No Type Parameters -Implemented Interfaces: interface java.lang.Cloneable interface java.io.Serializable Inheritance Path: java.lang.Object Annotations: -- No Annotations --

Since arrays are runtime objects, all of the type information is defined by the Java virtual machine. In particular, arrays implement Cloneable and java.io.Serializable and their direct superclass is always Object.
$ java ClassDeclarationSpy java.io.InterruptedIOException Class: java.io.InterruptedIOException Modifiers: public Type Parameters: -- No Type Parameters -Implemented Interfaces: -- No Implemented Interfaces -Inheritance Path: java.io.IOException java.lang.Exception java.lang.Throwable java.lang.Object Annotations: -- No Annotations --

From the inheritance path, it may be deduced that java.io.InterruptedIOException is a checked exception because RuntimeException is not present.
$ java ClassDeclarationSpy java.security.Identity Class: java.security.Identity Modifiers: public abstract Type Parameters: -- No Type Parameters -Implemented Interfaces: interface java.security.Principal interface java.io.Serializable Inheritance Path: java.lang.Object Annotations: @java.lang.Deprecated()

This output shows that java.security.Identity, a deprecated API, possesses the annotation java.lang.Deprecated. This may be used by reflective code to detect deprecated APIs.

Note: Not all annotations are available via reflection. Only those which have a java.lang.annotation.RetentionPolicy of RUNTIME are accessible. Of the three annotations pre-defined in the language @Deprecated, @Override, and @SuppressWarnings only @Deprecated is available at runtime. 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 table provides a summary of all the member-locating methods and their characteristics.

10

Class Methods for Locating Members List of Inherited Private Class API Member members? members? members? getDeclaredField() no no yes getField() no yes no Field getDeclaredFields() yes no yes getFields() yes yes no getDeclaredMethod() no no yes getMethod() no yes no Method getDeclaredMethods() yes no yes getMethods() yes yes no getDeclaredConstructor() no N/A1 yes 1 getConstructor() no N/A no Constructor 1 getDeclaredConstructors() yes N/A yes 1 getConstructors() yes N/A 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 import import import import java.lang.reflect.Constructor; java.lang.reflect.Field; java.lang.reflect.Method; java.lang.reflect.Member; 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])) {

11

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

12

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:

13

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

14

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

Troubleshooting The following examples show typical errors which may be encountered when reflecting on classes.

Compiler Warning: "Note: ... uses unchecked or unsafe operations"


When a method is invoked, the types of the argument values are checked and possibly converted. ClassWarning invokes getMethod() to cause a typical unchecked conversion warning:

15

import java.lang.reflect.Method; public class ClassWarning { void m() { try { Class c = ClassWarning.class; Method m = c.getMethod("m"); // warning // production code should handle this exception more gracefully } catch (NoSuchMethodException x) { x.printStackTrace(); } } } $ javac ClassWarning.java Note: ClassWarning.java uses unchecked or unsafe operations. Note: Recompile with -Xlint:unchecked for details. $ javac -Xlint:unchecked ClassWarning.java ClassWarning.java:7: warning: [unchecked] unchecked call to getMethod(java.lang.String,java.lang.Class<? >...) as a member of the raw type java.lang.Class Method m = c.getMethod("m"); // warning ^ 1 warning

Many library methods have been retrofitted with generic declarations including several in Class. Since c is declared as a raw type (has no type parameters) and the corresponding parameter of getMethod() is a parameterized type, an unchecked conversion occurs. The compiler is required to generate a warning. (See The Java Language Specification, Third Edition, sections 5.1.9 and 5.3.) There are two possible solutions. The more preferable it to modify the declaration of c to include an appropriate generic type. In this case, the declaration should be:
Class<?> c = warn.getClass();

Alternatively, the warning could be explicitly suppressed using the predefined annotation @SuppressWarnings preceding the problematic statement.
Class c = ClassWarning.class; @SuppressWarnings("unchecked") Method m = c.getMethod("m"); // warning gone

16

Tip: As a general principle, warnings should not be ignored as they may indicate the presence of a bug. Parameterized declarations should be used as appropriate. If that is not possible (perhaps because an application must interact with a library vendor's code), annotate the offending line using @SuppressWarnings.

InstantiationException when the Constructor is Not Accessible


will throw an InstantiationException if an attempt is made to create a new instance of the class and the zeroargument constructor is not visible. The ClassTrouble example illustrates the resulting stack trace.
Class.newInstance() class Cls { private Cls() {} } public class ClassTrouble { public static void main(String... args) { try { Class<?> c = Class.forName("Cls"); c.newInstance(); // InstantiationException // production code should handle these exceptions more gracefully } catch (InstantiationException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } catch (ClassNotFoundException x) { x.printStackTrace(); } } } $ java ClassTrouble java.lang.IllegalAccessException: Class ClassTrouble can not access a member of class Cls with modifiers "private" at sun.reflect.Reflection.ensureMemberAccess(Refle ction.java:65) at java.lang.Class.newInstance0(Class.java:349) at java.lang.Class.newInstance(Class.java:308) at ClassTrouble.main(ClassTrouble.java:9)

17

behaves very much like the new keyword and will fail for the same reasons new would fail. The typical solution in reflection is to take advantage of the java.lang.reflect.AccessibleObject class which provides the ability to suppress access control checks; however, this approach will not work because java.lang.Class does not extend AccessibleObject. The only solution is to modify the code to use Constructor.newInstance() which does extend AccessibleObject.
Class.newInstance()

Tip: In general, it is preferable to use Constructor.newInstance() for the reasons described in the Creating New Class Instances section in the Members lesson.

Additional examples of potential problems using Constructor.newInstance() may be found in the Constructor Troubleshooting section of the Members lesson.

Fields A field is a class, interface, or enum with an associated value. Methods in the java.lang.reflect.Field class can retrieve information about the field, such as its name, type, modifiers, and annotations. (The section Examining Class Modifiers and Types in the Classes lesson describes how to retrieve annotations.) There are also methods which enable dynamic access and modification of the value of the field. These tasks are covered in the following sections: Obtaining Field Types describes how to get the declared and generic types of a field Retrieving and Parsing Field Modifiers shows how to get portions of the field declaration such as public or transient Getting and Setting Field Values illustrates how to access field values Troubleshooting describes some common coding errors which may cause confusion

When writing an application such as a class browser, it might be useful to find out which fields belong to a particular class. A class's fields are identified by invoking Class.getFields(). The getFields() method returns an array of Field objects containing one object per accessible public field.

18

A public field is accessible if it is a member of either: this class a superclass of this class an interface implemented by this class an interface extended from an interface implemented by this class

A field may be a class (instance) field, such as java.io.Reader.lock , a static field, such as java.lang.Integer.MAX_VALUE , or an enum constant, such as java.lang.Thread.State.WAITING.

Obtaining Field Types A field may be either of primitive or reference type. There are eight primitive types: boolean, byte, short, int, long, char, float, and double. A reference type is anything that is a direct or indirect subclass of java.lang.Object including interfaces, arrays, and enumerated types. The FieldSpy example prints the field's type and generic type given a fully-qualified binary class name and field name.
import java.lang.reflect.Field; import java.util.List; public class FieldSpy<T> { public boolean[][] b = {{ false, false }, { true, true } }; public String name = "Alice"; public List<Integer> list; public T val; public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); Field f = c.getField(args[1]); System.out.format("Type: %s%n", f.getType()); System.out.format("GenericType: %s%n", f.getGenericType()); // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } catch (NoSuchFieldException x) { x.printStackTrace(); }

19

Sample output to retrieve the type of the three public fields in this class (b, name, and the parameterized type list), follows. User input is in italics.
$ java FieldSpy FieldSpy b Type: class [[Z GenericType: class [[Z $ java FieldSpy FieldSpy name Type: class java.lang.String GenericType: class java.lang.String $ java FieldSpy FieldSpy list Type: interface java.util.List GenericType: java.util.List<java.lang.Integer> $ java FieldSpy FieldSpy val Type: class java.lang.Object GenericType: T

The type for the field b is two-dimensional array of boolean. The syntax for the type name is described in Class.getName(). The type for the field val is reported as java.lang.Object because generics are implemented via type erasure which removes all information regarding generic types during compilation. Thus T is replaced by the upper bound of the type variable, in this case, java.lang.Object. will consult the Signature Attribute in the class file if it's present. If the attribute isn't available, it falls back on Field.getType() which was not changed by the introduction of generics. The other methods in reflection with name getGenericFoo for some value of Foo are implemented similarly.
Field.getGenericType()

Retrieving and Parsing Field Modifiers There are several modifiers that may be part of a field declaration:
Access modifiers: public, protected, and private Field-specific modifiers governing runtime behavior: transient and volatile Modifier restricting to one instance: static Modifier prohibiting value modification: final Annotations

The method Field.getModifiers() can be used to return the integer representing the set of declared modifiers for the field. The bits

20

representing the modifiers in this integer are defined in java.lang.reflect.Modifier. The FieldModifierSpy example illustrates how to search for fields with a given modifier. It also determines whether the located field is synthetic (compiler-generated) or is an enum constant by invoking Field.isSynthetic() and Field.isEnumCostant() respectively.
import java.lang.reflect.Field; import java.lang.reflect.Modifier; import static java.lang.System.out; enum Spy { BLACK , WHITE } public class FieldModifierSpy { volatile int share; int instance; class Inner {} public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); int searchMods = 0x0; for (int i = 1; i < args.length; i++) { searchMods |= modifierFromString(args[i]); } Field[] flds = c.getDeclaredFields(); out.format("Fields in Class '%s' containing modifiers: %s%n", c.getName(), Modifier.toString(searchMods)); boolean found = false; for (Field f : flds) { int foundMods = f.getModifiers(); // Require all of the requested modifiers to be present if ((foundMods & searchMods) == searchMods) { out.format("%-8s [ synthetic=%-5b enum_constant=%-5b ]%n", f.getName(), f.isSynthetic(), f.isEnumConstant()); found = true; } } if (!found) { out.format("No matching fields%n"); }

21

// production code should handle this exception more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } private static int modifierFromString(String s) { int m = 0x0; if ("public".equals(s)) Modifier.PUBLIC; else if ("protected".equals(s)) Modifier.PROTECTED; else if ("private".equals(s)) Modifier.PRIVATE; else if ("static".equals(s)) Modifier.STATIC; else if ("final".equals(s)) Modifier.FINAL; else if ("transient".equals(s)) Modifier.TRANSIENT; else if ("volatile".equals(s)) Modifier.VOLATILE; return m; } }

m |= m |= m |= m |= m |= m |= m |=

Sample output follows:


$ java FieldModifierSpy FieldModifierSpy volatile Fields in Class 'FieldModifierSpy' containing modifiers: volatile share [ synthetic=false enum_constant=false ] $ java FieldModifierSpy Spy public Fields in Class 'Spy' containing modifiers: public BLACK [ synthetic=false enum_constant=true ] WHITE [ synthetic=false enum_constant=true ] $ java FieldModifierSpy FieldModifierSpy\$Inner final Fields in Class 'FieldModifierSpy$Inner' containing modifiers: final this$0 [ synthetic=true enum_constant=false ] $ java FieldModifierSpy Spy private static final Fields in Class 'Spy' containing modifiers: private static final $VALUES [ synthetic=true enum_constant=false ]

Notice that some fields are reported even though they are not declared in the original code. This is because the compiler will generate some synthetic fields which are needed during runtime. To test whether a field is synthetic, the example invokes Field.isSynthetic(). The set of 22

synthetic fields is compiler-dependent; however commonly used fields include this$0 for inner classes (i.e. nested classes that are not static member classes) to reference the outermost enclosing class and $VALUES used by enums to implement the implicitly defined static method values(). The names of synthetic class members are not specified and may not be the same in all compiler implementations or releases. These and other synthetic fields will be included in the array returned by Class.getDeclaredFields() but not identified by Class.getField() since synthetic members are not typically public. Because Field implements the interface
java.lang.reflect.AnnotatedElement,

it is possible to retrieve any

runtime annotation with


java.lang.annotation.RetentionPolicy.RUNTIME.

For an example of obtaining annotations see the section Examining Class Modifiers and Types

Getting and Setting Field Values Given an instance of a class, it is possible to use reflection to set the values of fields in that class. This is typically done only in special circumstances when setting the values in the usual way is not possible. Because such access usually violates the design intentions of the class, it should be used with the utmost discretion. The Book class illustrates how to set the values for long, array, and enum field types. Methods for getting and setting other primitive types are described in Field.
import java.lang.reflect.Field; import java.util.Arrays; import static java.lang.System.out; enum Tweedle { DEE, DUM } public class Book { public long chapters = 0; public String[] characters = { "Alice", "White Rabbit" }; public Tweedle twin = Tweedle.DEE; public static void main(String... args) { Book book = new Book(); String fmt = "%6S: %-12s = %s%n"; try { Class<?> c = book.getClass();

23

Field chap = c.getDeclaredField("chapters"); out.format(fmt, "before", "chapters", book.chapters); chap.setLong(book, 12); out.format(fmt, "after", "chapters", chap.getLong(book)); Field chars = c.getDeclaredField("characters"); out.format(fmt, "before", "characters", Arrays.asList(book.characters)); String[] newChars = { "Queen", "King" }; chars.set(book, newChars); out.format(fmt, "after", "characters", Arrays.asList(book.characters)); Field t = c.getDeclaredField("twin"); out.format(fmt, "before", "twin", book.twin); t.set(book, Tweedle.DUM); out.format(fmt, "after", "twin", t.get(book)); // production code should handle these exceptions more gracefully } catch (NoSuchFieldException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } } }

This is the corresponding output:


$ java Book BEFORE: chapters AFTER: chapters BEFORE: characters AFTER: characters BEFORE: twin AFTER: twin = = = = = = 0 12 [Alice, White Rabbit] [Queen, King] DEE DUM

Note: Setting a field's value via reflection has a certain amount of performance overhead because various operations must occur such as validating access permissions. From the runtime's point of view, the effects are the same, and the operation is as atomic as if the value was changed in the class code directly. 24

Use of reflection can cause some runtime optimizations to be lost. For example, the following code is highly likely be optimized by a Java virtual machine:
int x = 1; x = 2; x = 3;

Equivalent code using Field.set*() may not.

Troubleshooting Here are a few common problems encountered by developers with explanations for why the occur and how to resolve them.

IllegalArgumentException due to Inconvertible Types


The FieldTrouble example will generate an IllegalArgumentException. Field.setInt() is invoked to set a field that is of the reference type Integer with a value of primitive type. In the non-reflection equivalent Integer val = 42, the compiler would convert (or box) the primitive type 42 to a reference type as new Integer(42) so that its type checking will accept the statement. When using reflection, type checking only occurs at runtime so there is no opportunity to box the value.
import java.lang.reflect.Field; public class FieldTrouble { public Integer val; public static void main(String... args) { FieldTrouble ft = new FieldTrouble(); try { Class<?> c = ft.getClass(); Field f = c.getDeclaredField("val"); f.setInt(ft, 42); // IllegalArgumentException // production code should handle these exceptions more gracefully } catch (NoSuchFieldException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } } }

25

$ java FieldTrouble Exception in thread "main" java.lang.IllegalArgumentException: Can not set java.lang.Object field FieldTrouble.val to (long)42 at sun.reflect.UnsafeFieldAccessorImpl.throwSetIll egalArgumentException(UnsafeFieldAccessorImpl.j ava:146) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIll egalArgumentException(UnsafeFieldAccessorImpl.j ava:174) at sun.reflect.UnsafeObjectFieldAccessorImpl.setLo ng(UnsafeObjectFieldAccessorImpl.java:102) at java.lang.reflect.Field.setLong(Field.java:831) at FieldTrouble.main(FieldTrouble.java:11)

To eliminate this exception, the problematic line should be replaced by the following invocation of Field.set(Object obj, Object value):
f.set(ft, new Integer(43));

Tip: When using reflection to set or get a field, the compiler does not have an opportunity to perform boxing. It can only convert types that are related as described by the specification for Class.isAssignableFrom(). The example is expected to fail because isAssignableFrom() will return false in this test which can be used programmatically to verify whether a particular conversion is possible:
Integer.class.isAssignableFrom(int. class) == false

Similarly, automatic conversion from primitive to reference type is also impossible in reflection.
int.class.isAssignableFrom(Integer. class) == false

NoSuchFieldException for Non-Public Fields


The astute reader may notice that if the FieldSpy example shown earlier is used to get information on a non-public field, it will fail:

26

$ java FieldSpy java.lang.String count java.lang.NoSuchFieldException: count at java.lang.Class.getField(Class.java:1519) at FieldSpy.main(FieldSpy.java:12)

Tip: The Class.getField() and Class.getFields() methods return the public member field(s) of the class, enum, or interface represented by the Class object. To retrieve all fields declared (but not inherited) in the Class, use the Class.getDeclaredFields() method.

IllegalAccessException when Modifying Final Fields


An IllegalAccessException may be thrown if an attempt is made to get or set the value of a private or otherwise inaccessible field or to set the value of a final field (regardless of its access modifiers). The FieldTroubleToo example illustrates the type of stack trace which results from attempting to set a final field.
import java.lang.reflect.Field; public class FieldTroubleToo { public final boolean b = true; public static void main(String... args) { FieldTroubleToo ft = new FieldTroubleToo(); try { Class<?> c = ft.getClass(); Field f = c.getDeclaredField("b"); // f.setAccessible(true); // solution f.setBoolean(ft, Boolean.FALSE); // IllegalAccessException // production code should handle these exceptions more gracefully } catch (NoSuchFieldException x) { x.printStackTrace(); } catch (IllegalArgumentException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } } } $ java FieldTroubleToo

27

java.lang.IllegalAccessException: Can not set final boolean field FieldTroubleToo.b to (boolean)false at sun.reflect.UnsafeFieldAccessorImpl.throwFinalF ieldIllegalAccessException(UnsafeFieldAccessorI mpl.java:55) at sun.reflect.UnsafeFieldAccessorImpl.throwFinalF ieldIllegalAccessException(UnsafeFieldAccessorI mpl.java:63) at sun.reflect.UnsafeQualifiedBooleanFieldAccessor Impl.setBoolean(UnsafeQualifiedBooleanFieldAcce ssorImpl.java:78) at java.lang.reflect.Field.setBoolean(Field.java:6 86) at FieldTroubleToo.main(FieldTroubleToo.java:12)

Tip: An access restriction exists which prevents final fields from being set after initialization of the class. However, Field is declared to extend AccessibleObject which provides the ability to suppress this check. If AccessibleObject.setAccessible() succeeds, then subsequent operations on this field value will not fail do to this problem. This may have unexpected side-effects; for example, sometimes the original value will continue to be used by some sections of the application even though the value has been modified. AccessibleObject.setAccessible() will only succeed if the operation is allowed by the security context. Methods A method contains executable code which may be invoked. Methods are inherited and in non-reflective code behaviors such as overloading, overriding, and hiding are enforced by the compiler. In contrast, reflective code makes it possible for method selection to be restricted to a specific class without considering its superclasses. Superclass methods may be accessed but it is possible to determine their declaring class; this is impossible to discover programmatically without reflection and is the source of many subtle bugs. The java.lang.reflect.Method class provides APIs to access information about a method's modifiers, return type, parameters, 28

annotations, and thrown exceptions. It also be used to invoke methods. These topics are covered by the following sections: Obtaining Method Type Information shows how to enumerate methods declared in a class and obtains type information Retrieving and Parsing Method Modifiers describes how to access and decode modifiers and other information associated with the method Invoking Methods illustrates how to execute a method and obtain its return value Troubleshooting covers common errors encountered when finding or invoking methods

Obtaining Method Type Information A method declaration includes the name, modifiers, parameters, return type, and list of throwable exceptions. The java.lang.reflect.Method class provides a way to obtain this information. The MethodSpy example illustrates how to enumerate all of the declared methods in a given class and retrieve the return, parameter, and exception types for all the methods of the given name.
import java.lang.reflect.Method; import java.lang.reflect.Type; import static java.lang.System.out; public class MethodSpy { private static final String %s%n"; fmt = "%24s:

// for the morbidly curious <E extends RuntimeException> void genericThrow() throws E {} public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); Method[] allMethods = c.getDeclaredMethods(); for (Method m : allMethods) { if (!m.getName().equals(args[1])) { continue; } out.format("%s%n", m.toGenericString());

29

out.format(fmt, "ReturnType", m.getReturnType()); out.format(fmt, "GenericReturnType", m.getGenericReturnType()); Class<?>[] pType = m.getParameterTypes(); Type[] gpType = m.getGenericParameterTypes(); for (int i = 0; i < pType.length; i+ +) { out.format(fmt,"ParameterType", pType[i]); out.format(fmt,"GenericParameterType", gpType[i]); } Class<?>[] xType = m.getExceptionTypes(); Type[] gxType = m.getGenericExceptionTypes(); for (int i = 0; i < xType.length; i+ +) { out.format(fmt,"ExceptionType", xType[i]); out.format(fmt,"GenericExceptionType", gxType[i]); } } // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } }

Here is the output for Class.getConstructor() which is an example of a method with parameterized types and a variable number of parameters.
$ java MethodSpy java.lang.Class getConstructor public java.lang.reflect.Constructor<T> java.lang.Class.getConstructor(java.lang.Class< ?>[]) throws java.lang.NoSuchMethodException,java.lang.Secur ityException ReturnType: class java.lang.reflect.Constructor GenericReturnType: java.lang.reflect.Constructor<T> ParameterType: class [Ljava.lang.Class; GenericParameterType: java.lang.Class<?>[]

30

ExceptionType: class java.lang.NoSuchMethodException GenericExceptionType: class java.lang.NoSuchMethodException ExceptionType: class java.lang.SecurityException GenericExceptionType: class java.lang.SecurityException

This is the actual declaration of the method in source code:


public Constructor<T> getConstructor(Class<? >... parameterTypes)

First note that the return and parameter types are generic. Method.getGenericReturnType() will consult the Signature Attribute in the class file if it's present. If the attribute isn't available, it falls back on Method.getReturnType() which was not changed by the introduction of generics. The other methods with name getGenericFoo() for some value of Foo in reflection are implemented similarly. Next, notice that the last (and only) parameter, parameterType, is of variable arity (has a variable number of parameters) of type java.lang.Class. It is represented as a single-dimension array of type java.lang.Class. This can be distinguished from a parameter that is explicitly an array of java.lang.Class by invoking Method.isVarArgs(). The syntax for the returned values of Method.get*Types() is described in Class.getName(). The following example illustrates a method with a generic return type.
$ java MethodSpy java.lang.Class cast public T java.lang.Class.cast(java.lang.Object) ReturnType: class java.lang.Object GenericReturnType: T ParameterType: class java.lang.Object GenericParameterType: class java.lang.Object

The generic return type for the method Class.cast() is reported as java.lang.Object because generics are implemented via type erasure which removes all information regarding generic types during compilation. The erasure of T is defined by the declaration of Class:
public final class Class<T> implements ...

Thus T is replaced by the upper bound of the type variable, in this case, java.lang.Object.

31

The last example illustrates the output for a method with multiple overloads.
$ java MethodSpy java.io.PrintStream format public java.io.PrintStream java.io.PrintStream.format(java.util.Locale,jav a.lang.String,java.lang.Object[]) ReturnType: class java.io.PrintStream GenericReturnType: class java.io.PrintStream ParameterType: class java.util.Locale GenericParameterType: class java.util.Locale ParameterType: class java.lang.String GenericParameterType: class java.lang.String ParameterType: class [Ljava.lang.Object; GenericParameterType: class [Ljava.lang.Object; public java.io.PrintStream java.io.PrintStream.format(java.lang.String,jav a.lang.Object[]) ReturnType: class java.io.PrintStream GenericReturnType: class java.io.PrintStream ParameterType: class java.lang.String GenericParameterType: class java.lang.String ParameterType: class [Ljava.lang.Object; GenericParameterType: class [Ljava.lang.Object;

If multiple overloads of the same method name are discovered, they are all returned by Class.getDeclaredMethods(). Since format() has two overloads (with with a Locale and one without), both are shown by MethodSpy.

Note: Method.getGenericExceptionTypes() exists because it is actually possible to declare a method with a generic exception type. However this is rarely used since it is not possible to catch a generic exception type.

Retrieving and Parsing Method Modifiers There a several modifiers that may be part of a method declaration:

Access modifiers: public, protected, and private Modifier restricting to one instance: static 32

Modifier prohibiting value modification: final Modifier requiring override: abstract Modifier preventing reentrancy: synchronized Modifier indicating implementation in another programming language: native Modifier forcing strict floating point behavior: strictfp Annotations

The MethodModifierSpy example lists the modifiers of a method with a given name. It also displays whether the method is synthetic (compilergenerated), of variable arity, or a bridge method (compiler-generated to support generic interfaces).
import java.lang.reflect.Method; import java.lang.reflect.Modifier; import static java.lang.System.out; public class MethodModifierSpy { private static int count; private static synchronized void inc() { count++; } private static synchronized int cnt() { return count; } public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); Method[] allMethods = c.getDeclaredMethods(); for (Method m : allMethods) { if (!m.getName().equals(args[1])) { continue; } out.format("%s%n", m.toGenericString()); out.format(" Modifiers: %s%n", Modifier.toString(m.getModifiers())); out.format(" [ synthetic=%-5b var_args=%-5b bridge=%-5b ]%n", m.isSynthetic(), m.isVarArgs(), m.isBridge()); inc(); } out.format("%d matching overload%s found %n", cnt(), (cnt() == 1 ? "" : "s")); // production code should handle this exception more gracefully } catch (ClassNotFoundException x) { x.printStackTrace();

33

} } }

A few examples of the output MethodMdifierSpy produces follow.


$ java MethodModifierSpy java.lang.Object wait public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException Modifiers: public final native [ synthetic=false var_args=false bridge=false ] public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException Modifiers: public final [ synthetic=false var_args=false bridge=false ] public final void java.lang.Object.wait() throws java.lang.InterruptedException Modifiers: public final [ synthetic=false var_args=false bridge=false ] 3 matching overloads found $ java MethodModifierSpy java.lang.StrictMath toRadians public static double java.lang.StrictMath.toRadians(double) Modifiers: public static strictfp [ synthetic=false var_args=false bridge=false ] 1 matching overload found $ java MethodModifierSpy MethodModifierSpy inc private synchronized void MethodModifierSpy.inc() Modifiers: private synchronized [ synthetic=false var_args=false bridge=false ] 1 matching overload found $ java MethodModifierSpy java.lang.Class getConstructor public java.lang.reflect.Constructor<T> java.lang.Class.getConstructor(java.lang.Class< T>[]) throws java.lang.NoSuchMethodException,java.lang.Secur ityException Modifiers: public transient [ synthetic=false var_args=true bridge=false ] 1 matching overload found $ java MethodModifierSpy java.lang.String compareTo public int java.lang.String.compareTo(java.lang.String) Modifiers: public

34

[ synthetic=false var_args=false bridge=false ] public int java.lang.String.compareTo(java.lang.Object) Modifiers: public volatile [ synthetic=true var_args=false bridge=true ] 2 matching overloads found

Note that Method.isVarArgs() returns true for Class.getConstructor(). This indicates that the method declaration looks like this:
public Constructor<T> getConstructor(Class<? >... parameterTypes)

not like this:


public Constructor<T> getConstructor(Class<?> [] parameterTypes)

Notice that the output for String.compareTo() contains two methods. The method declared in String.java:
public int compareTo(String anotherString);

and a second synthetic or compiler-generated bridge method. This occurs because String implements the parameterized interface Comparable. During type erasure, the argument type of the inherited method Comparable.compareTo() is changed from java.lang.Object to java.lang.String. Since the parameter types for the compareTo methods in Comparable and String no longer match after erasure, overriding can not occur. In all other circumstances, this would produce a compile-time error because the interface is not implemented. The addition of the bridge method avoids this problem. implements java.lang.reflect.AnnotatedElement. Thus any runtime annotations with java.lang.annotation.RetentionPolicy.RUNTIME may be retrieved. For an example of obtaining annotations see the section Examining Class Modifiers and Types.
Method

Getting and Setting Field Values Given an instance of a class, it is possible to use reflection to set the values of fields in that class. This is typically done only in special circumstances

35

when setting the values in the usual way is not possible. Because such access usually violates the design intentions of the class, it should be used with the utmost discretion. The Book class illustrates how to set the values for long, array, and enum field types. Methods for getting and setting other primitive types are described in Field.
import java.lang.reflect.Field; import java.util.Arrays; import static java.lang.System.out; enum Tweedle { DEE, DUM } public class Book { public long chapters = 0; public String[] characters = { "Alice", "White Rabbit" }; public Tweedle twin = Tweedle.DEE; public static void main(String... args) { Book book = new Book(); String fmt = "%6S: %-12s = %s%n"; try { Class<?> c = book.getClass(); Field chap = c.getDeclaredField("chapters"); out.format(fmt, "before", "chapters", book.chapters); chap.setLong(book, 12); out.format(fmt, "after", "chapters", chap.getLong(book)); Field chars = c.getDeclaredField("characters"); out.format(fmt, "before", "characters", Arrays.asList(book.characters)); String[] newChars = { "Queen", "King" }; chars.set(book, newChars); out.format(fmt, "after", "characters", Arrays.asList(book.characters)); Field t = c.getDeclaredField("twin"); out.format(fmt, "before", "twin", book.twin); t.set(book, Tweedle.DUM); out.format(fmt, "after", "twin", t.get(book));

36

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

This is the corresponding output:


$ java Book BEFORE: chapters AFTER: chapters BEFORE: characters AFTER: characters BEFORE: twin AFTER: twin = = = = = = 0 12 [Alice, White Rabbit] [Queen, King] DEE DUM

Note: Setting a field's value via reflection has a certain amount of performance overhead because various operations must occur such as validating access permissions. From the runtime's point of view, the effects are the same, and the operation is as atomic as if the value was changed in the class code directly. Use of reflection can cause some runtime optimizations to be lost. For example, the following code is highly likely be optimized by a Java virtual machine:
int x = 1; x = 2; x = 3;

Equivalent code using Field.set*() may not.

Troubleshooting Here are a few common problems encountered by developers with explanations for why the occur and how to resolve them.

IllegalArgumentException due to Inconvertible Types


The FieldTrouble example will generate an IllegalArgumentException. Field.setInt() is invoked to set a field

37

that is of the reference type Integer with a value of primitive type. In the non-reflection equivalent Integer val = 42, the compiler would convert (or box) the primitive type 42 to a reference type as new Integer(42) so that its type checking will accept the statement. When using reflection, type checking only occurs at runtime so there is no opportunity to box the value.
import java.lang.reflect.Field; public class FieldTrouble { public Integer val; public static void main(String... args) { FieldTrouble ft = new FieldTrouble(); try { Class<?> c = ft.getClass(); Field f = c.getDeclaredField("val"); f.setInt(ft, 42); // IllegalArgumentException // production code should handle these exceptions more gracefully } catch (NoSuchFieldException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } } } $ java FieldTrouble Exception in thread "main" java.lang.IllegalArgumentException: Can not set java.lang.Object field FieldTrouble.val to (long)42 at sun.reflect.UnsafeFieldAccessorImpl.throwSetIll egalArgumentException(UnsafeFieldAccessorImpl.j ava:146) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIll egalArgumentException(UnsafeFieldAccessorImpl.j ava:174) at sun.reflect.UnsafeObjectFieldAccessorImpl.setLo ng(UnsafeObjectFieldAccessorImpl.java:102) at java.lang.reflect.Field.setLong(Field.java:831) at FieldTrouble.main(FieldTrouble.java:11)

To eliminate this exception, the problematic line should be replaced by the following invocation of Field.set(Object obj, Object value):

38

f.set(ft, new Integer(43));

Tip: When using reflection to set or get a field, the compiler does not have an opportunity to perform boxing. It can only convert types that are related as described by the specification for Class.isAssignableFrom(). The example is expected to fail because isAssignableFrom() will return false in this test which can be used programmatically to verify whether a particular conversion is possible:
Integer.class.isAssignableFrom(int. class) == false

Similarly, automatic conversion from primitive to reference type is also impossible in reflection.
int.class.isAssignableFrom(Integer. class) == false

NoSuchFieldException for Non-Public Fields


The astute reader may notice that if the FieldSpy example shown earlier is used to get information on a non-public field, it will fail:
$ java FieldSpy java.lang.String count java.lang.NoSuchFieldException: count at java.lang.Class.getField(Class.java:1519) at FieldSpy.main(FieldSpy.java:12)

Tip: The Class.getField() and Class.getFields() methods return the public member field(s) of the class, enum, or interface represented by the Class object. To retrieve all fields declared (but not inherited) in the Class, use the Class.getDeclaredFields() method.

IllegalAccessException when Modifying Final Fields


An IllegalAccessException may be thrown if an attempt is made to get or set the value of a private or otherwise inaccessible field or to set the value of a final field (regardless of its access modifiers).

39

The FieldTroubleToo example illustrates the type of stack trace which results from attempting to set a final field.
import java.lang.reflect.Field; public class FieldTroubleToo { public final boolean b = true; public static void main(String... args) { FieldTroubleToo ft = new FieldTroubleToo(); try { Class<?> c = ft.getClass(); Field f = c.getDeclaredField("b"); // f.setAccessible(true); // solution f.setBoolean(ft, Boolean.FALSE); // IllegalAccessException // production code should handle these exceptions more gracefully } catch (NoSuchFieldException x) { x.printStackTrace(); } catch (IllegalArgumentException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } } } $ java FieldTroubleToo java.lang.IllegalAccessException: Can not set final boolean field FieldTroubleToo.b to (boolean)false at sun.reflect.UnsafeFieldAccessorImpl.throwFinalF ieldIllegalAccessException(UnsafeFieldAccessorI mpl.java:55) at sun.reflect.UnsafeFieldAccessorImpl.throwFinalF ieldIllegalAccessException(UnsafeFieldAccessorI mpl.java:63) at sun.reflect.UnsafeQualifiedBooleanFieldAccessor Impl.setBoolean(UnsafeQualifiedBooleanFieldAcce ssorImpl.java:78) at java.lang.reflect.Field.setBoolean(Field.java:6 86) at FieldTroubleToo.main(FieldTroubleToo.java:12)

Tip: An access restriction exists which prevents final fields from being set after initialization of the class.

40

However, Field is declared to extend AccessibleObject which provides the ability to suppress this check. If AccessibleObject.setAccessible() succeeds, then subsequent operations on this field value will not fail do to this problem. This may have unexpected side-effects; for example, sometimes the original value will continue to be used by some sections of the application even though the value has been modified. AccessibleObject.setAccessible() will only succeed if the operation is allowed by the security context.

Methods A method contains executable code which may be invoked. Methods are inherited and in non-reflective code behaviors such as overloading, overriding, and hiding are enforced by the compiler. In contrast, reflective code makes it possible for method selection to be restricted to a specific class without considering its superclasses. Superclass methods may be accessed but it is possible to determine their declaring class; this is impossible to discover programmatically without reflection and is the source of many subtle bugs. The java.lang.reflect.Method class provides APIs to access information about a method's modifiers, return type, parameters, annotations, and thrown exceptions. It also be used to invoke methods. These topics are covered by the following sections: Obtaining Method Type Information shows how to enumerate methods declared in a class and obtains type information Retrieving and Parsing Method Modifiers describes how to access and decode modifiers and other information associated with the method Invoking Methods illustrates how to execute a method and obtain its return value Troubleshooting covers common errors encountered when finding or invoking methods

Obtaining Method Type Information

41

A method declaration includes the name, modifiers, parameters, return type, and list of throwable exceptions. The java.lang.reflect.Method class provides a way to obtain this information. The MethodSpy example illustrates how to enumerate all of the declared methods in a given class and retrieve the return, parameter, and exception types for all the methods of the given name.
import java.lang.reflect.Method; import java.lang.reflect.Type; import static java.lang.System.out; public class MethodSpy { private static final String %s%n"; fmt = "%24s:

// for the morbidly curious <E extends RuntimeException> void genericThrow() throws E {} public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); Method[] allMethods = c.getDeclaredMethods(); for (Method m : allMethods) { if (!m.getName().equals(args[1])) { continue; } out.format("%s%n", m.toGenericString()); out.format(fmt, "ReturnType", m.getReturnType()); out.format(fmt, "GenericReturnType", m.getGenericReturnType()); Class<?>[] pType = m.getParameterTypes(); Type[] gpType = m.getGenericParameterTypes(); for (int i = 0; i < pType.length; i+ +) { out.format(fmt,"ParameterType", pType[i]); out.format(fmt,"GenericParameterType", gpType[i]); } Class<?>[] xType = m.getExceptionTypes(); Type[] gxType = m.getGenericExceptionTypes();

42

+) { xType[i]);

for (int i = 0; i < xType.length; i+ out.format(fmt,"ExceptionType",

out.format(fmt,"GenericExceptionType", gxType[i]); } } // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } }

Here is the output for Class.getConstructor() which is an example of a method with parameterized types and a variable number of parameters.
$ java MethodSpy java.lang.Class getConstructor public java.lang.reflect.Constructor<T> java.lang.Class.getConstructor(java.lang.Class< ?>[]) throws java.lang.NoSuchMethodException,java.lang.Secur ityException ReturnType: class java.lang.reflect.Constructor GenericReturnType: java.lang.reflect.Constructor<T> ParameterType: class [Ljava.lang.Class; GenericParameterType: java.lang.Class<?>[] ExceptionType: class java.lang.NoSuchMethodException GenericExceptionType: class java.lang.NoSuchMethodException ExceptionType: class java.lang.SecurityException GenericExceptionType: class java.lang.SecurityException

This is the actual declaration of the method in source code:


public Constructor<T> getConstructor(Class<? >... parameterTypes)

First note that the return and parameter types are generic. Method.getGenericReturnType() will consult the Signature Attribute in the class file if it's present. If the attribute isn't available, it falls back on Method.getReturnType() which was not changed by the introduction of

43

generics. The other methods with name getGenericFoo() for some value of Foo in reflection are implemented similarly. Next, notice that the last (and only) parameter, parameterType, is of variable arity (has a variable number of parameters) of type java.lang.Class. It is represented as a single-dimension array of type java.lang.Class. This can be distinguished from a parameter that is explicitly an array of java.lang.Class by invoking Method.isVarArgs(). The syntax for the returned values of Method.get*Types() is described in Class.getName(). The following example illustrates a method with a generic return type.
$ java MethodSpy java.lang.Class cast public T java.lang.Class.cast(java.lang.Object) ReturnType: class java.lang.Object GenericReturnType: T ParameterType: class java.lang.Object GenericParameterType: class java.lang.Object

The generic return type for the method Class.cast() is reported as java.lang.Object because generics are implemented via type erasure which removes all information regarding generic types during compilation. The erasure of T is defined by the declaration of Class:
public final class Class<T> implements ...

Thus T is replaced by the upper bound of the type variable, in this case, java.lang.Object. The last example illustrates the output for a method with multiple overloads.
$ java MethodSpy java.io.PrintStream format public java.io.PrintStream java.io.PrintStream.format(java.util.Locale,jav a.lang.String,java.lang.Object[]) ReturnType: class java.io.PrintStream GenericReturnType: class java.io.PrintStream ParameterType: class java.util.Locale GenericParameterType: class java.util.Locale ParameterType: class java.lang.String GenericParameterType: class java.lang.String ParameterType: class [Ljava.lang.Object; GenericParameterType: class [Ljava.lang.Object;

44

public java.io.PrintStream java.io.PrintStream.format(java.lang.String,jav a.lang.Object[]) ReturnType: class java.io.PrintStream GenericReturnType: class java.io.PrintStream ParameterType: class java.lang.String GenericParameterType: class java.lang.String ParameterType: class [Ljava.lang.Object; GenericParameterType: class [Ljava.lang.Object;

If multiple overloads of the same method name are discovered, they are all returned by Class.getDeclaredMethods(). Since format() has two overloads (with with a Locale and one without), both are shown by MethodSpy.

Note: Method.getGenericExceptionTypes() exists because it is actually possible to declare a method with a generic exception type. However this is rarely used since it is not possible to catch a generic exception type.

Retrieving and Parsing Method Modifiers There a several modifiers that may be part of a method declaration: Access modifiers: public, protected, and private Modifier restricting to one instance: static Modifier prohibiting value modification: final Modifier requiring override: abstract Modifier preventing reentrancy: synchronized Modifier indicating implementation in another programming language: native Modifier forcing strict floating point behavior: strictfp Annotations

The MethodModifierSpy example lists the modifiers of a method with a given name. It also displays whether the method is synthetic (compilergenerated), of variable arity, or a bridge method (compiler-generated to support generic interfaces).
import java.lang.reflect.Method; import java.lang.reflect.Modifier;

45

import static java.lang.System.out; public class MethodModifierSpy { private static int count; private static synchronized void inc() { count++; } private static synchronized int cnt() { return count; } public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); Method[] allMethods = c.getDeclaredMethods(); for (Method m : allMethods) { if (!m.getName().equals(args[1])) { continue; } out.format("%s%n", m.toGenericString()); out.format(" Modifiers: %s%n", Modifier.toString(m.getModifiers())); out.format(" [ synthetic=%-5b var_args=%-5b bridge=%-5b ]%n", m.isSynthetic(), m.isVarArgs(), m.isBridge()); inc(); } out.format("%d matching overload%s found %n", cnt(), (cnt() == 1 ? "" : "s")); // production code should handle this exception more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } }

A few examples of the output MethodMdifierSpy produces follow.


$ java MethodModifierSpy java.lang.Object wait public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException Modifiers: public final native [ synthetic=false var_args=false bridge=false ] public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException Modifiers: public final

46

[ synthetic=false var_args=false bridge=false ] public final void java.lang.Object.wait() throws java.lang.InterruptedException Modifiers: public final [ synthetic=false var_args=false bridge=false ] 3 matching overloads found $ java MethodModifierSpy java.lang.StrictMath toRadians public static double java.lang.StrictMath.toRadians(double) Modifiers: public static strictfp [ synthetic=false var_args=false bridge=false ] 1 matching overload found $ java MethodModifierSpy MethodModifierSpy inc private synchronized void MethodModifierSpy.inc() Modifiers: private synchronized [ synthetic=false var_args=false bridge=false ] 1 matching overload found $ java MethodModifierSpy java.lang.Class getConstructor public java.lang.reflect.Constructor<T> java.lang.Class.getConstructor(java.lang.Class< T>[]) throws java.lang.NoSuchMethodException,java.lang.Secur ityException Modifiers: public transient [ synthetic=false var_args=true bridge=false ] 1 matching overload found $ java MethodModifierSpy java.lang.String compareTo public int java.lang.String.compareTo(java.lang.String) Modifiers: public [ synthetic=false var_args=false bridge=false ] public int java.lang.String.compareTo(java.lang.Object) Modifiers: public volatile [ synthetic=true var_args=false bridge=true ] 2 matching overloads found

Note that Method.isVarArgs() returns true for Class.getConstructor(). This indicates that the method declaration looks like this:
public Constructor<T> getConstructor(Class<? >... parameterTypes)

47

not like this:


public Constructor<T> getConstructor(Class<?> [] parameterTypes)

Notice that the output for String.compareTo() contains two methods. The method declared in String.java:
public int compareTo(String anotherString);

and a second synthetic or compiler-generated bridge method. This occurs because String implements the parameterized interface Comparable. During type erasure, the argument type of the inherited method Comparable.compareTo() is changed from java.lang.Object to java.lang.String. Since the parameter types for the compareTo methods in Comparable and String no longer match after erasure, overriding can not occur. In all other circumstances, this would produce a compile-time error because the interface is not implemented. The addition of the bridge method avoids this problem. implements java.lang.reflect.AnnotatedElement. Thus any runtime annotations with java.lang.annotation.RetentionPolicy.RUNTIME may be retrieved. For an example of obtaining annotations see the section Examining Class Modifiers and Types.
Method

Invoking Methods Reflection provides a means for invoking methods on a class. Typically, this would only be necessary if it is not possible to cast an instance of the class to the desired type in non-reflective code. Methods are invoked with java.lang.reflect.Method.invoke(). The first argument is the object instance on which this particular method is to be invoked. (If the method is static, the first argument should be null.) Subsequent arguments are the method's parameters. If the underlying method throws an exception, it will be wrapped by an java.lang.reflect.InvocationTargetException. The method's original exception may be retrieved using the exception chaining mechanism's InvocationTargetException.getCause() method.

Finding and Invoking a Method with a Specific Declaration


Consider a test suite which uses reflection to invoke private test methods in a given class. The Deet example searches for public methods in a class

48

which begin with the string "test", have a boolean return type, and a single Locale parameter. It then invokes each matching method.
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; import java.util.Locale; import static java.lang.System.out; import static java.lang.System.err; public class Deet<T> { private boolean testDeet(Locale l) { // getISO3Language() may throw a MissingResourceException out.format("Locale = %s, ISO Language Code = %s%n", l.getDisplayName(), l.getISO3Language()); return true; } private int testFoo(Locale l) { return 0; } private boolean testBar() { return true; } public static void main(String... args) { if (args.length != 4) { err.format("Usage: java Deet <classname> <langauge> <country> <variant>%n"); return; } try { Class<?> c = Class.forName(args[0]); Object t = c.newInstance(); Method[] allMethods = c.getDeclaredMethods(); for (Method m : allMethods) { String mname = m.getName(); if (!mname.startsWith("test") || (m.getGenericReturnType() != boolean.class)) { continue; } Type[] pType = m.getGenericParameterTypes(); if ((pType.length != 1) || Locale.class.isAssignableFrom(pType[0].getClass ())) { continue; } out.format("invoking %s()%n", mname); try { m.setAccessible(true);

49

Object o = m.invoke(t, new Locale(args[1], args[2], args[3])); out.format("%s() returned %b%n", mname, (Boolean) o); // Handle any exceptions thrown by method to be invoked. } catch (InvocationTargetException x) { Throwable cause = x.getCause(); err.format("invocation of %s failed: %s%n", mname, cause.getMessage()); } } // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } catch (InstantiationException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } } }

invokes getDeclaredMethods() which will return all methods explicitly declared in the class. Also, Class.isAssignableFrom() is used to determine whether the parameters of the located method are compatible with the desired invocation. Technically the code could have tested whether the following statement is true since Locale is final:
Deet Locale.class == pType[0].getClass()

However, Class.isAssignableFrom() is more general.


$ java Deet Deet ja JP JP invoking testDeet() Locale = Japanese (Japan,JP), ISO Language Code = jpn testDeet() returned true $ java Deet Deet xx XX XX invoking testDeet() invocation of testDeet failed: Couldn't find 3letter language code for xx

First, note that only testDeet() meets the declaration restrictions enforced by the code. Next, when testDeet() is passed an invalid argument it throws an unchecked java.util.MissingResourceException. In reflection, there is no 50

distinction in the handling of checked versus unchecked exceptions. They are all wrapped in an InvocationTargetException

Invoking Methods with a Variable Number of Arguments


may be used to pass a variable number of arguments to a method. The key concept to understand is that methods of variable arity are implemented as if the variable arguments are packed in an array.
Method.invoke()

The InvokeMain example illustrates how to invoke the main() entry point in any class and pass a set of arguments determined at runtime.
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Arrays; public class InvokeMain { public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); Class[] argTypes = new Class[] { String[].class }; Method main = c.getDeclaredMethod("main", argTypes); String[] mainArgs = Arrays.copyOfRange(args, 1, args.length); System.out.format("invoking %s.main() %n", c.getName()); main.invoke(null, (Object)mainArgs); // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } catch (NoSuchMethodException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } catch (InvocationTargetException x) { x.printStackTrace(); } } }

First, to find the main() method the code searches for a class with the name "main" with a single parameter that is an array of String Since main() is static, null is the first argument to Method.invoke(). The second argument is the array of arguments to be passed.
$ java InvokeMain Deet Deet ja JP JP

51

invoking Deet.main() invoking testDeet() Locale = Japanese (Japan,JP), ISO Language Code = jpn testDeet() returned true

This section contains examples of problems developers might encounter when using reflection to locate, invoke, or get information about methods.

NoSuchMethodException Due to Type Erasure


The MethodTrouble example illustrates what happens when type erasure is not taken into consideration by code which searches for a particular method in a class.
import java.lang.reflect.Method; public class MethodTrouble<T> { public void lookup(T t) {} public void find(Integer i) {} public static void main(String... args) { try { String mName = args[0]; Class cArg = Class.forName(args[1]); Class<?> c = (new MethodTrouble<Integer>()).getClass(); Method m = c.getMethod(mName, cArg); System.out.format("Found:%n %s%n", m.toGenericString()); // production code should handle these exceptions more gracefully } catch (NoSuchMethodException x) { x.printStackTrace(); } catch (ClassNotFoundException x) { x.printStackTrace(); } } } $ java MethodTrouble lookup java.lang.Integer java.lang.NoSuchMethodException: MethodTrouble.lookup(java.lang.Integer) at java.lang.Class.getMethod(Class.java:1605) at MethodTrouble.main(MethodTrouble.java:12) $ java MethodTrouble lookup java.lang.Object Found: public void MethodTrouble.lookup(T)

When a method is declared with a generic parameter type, the compiler will replace the generic type with its upper bound, in this case, the upper bound of T is Object. Thus,

52

when the code searches for lookup(Integer), no method is found, despite the fact that the instance of MethodTrouble was created as follows:
Class c = (new MethodTrouble()).getClass();

Searching for lookup(Object) succeeds as expected.


$ java MethodTrouble find java.lang.Integer Found: public void MethodTrouble.find(java.lang.Integer) $ java MethodTrouble find java.lang.Object java.lang.NoSuchMethodException: MethodTrouble.find(java.lang.Object) at java.lang.Class.getMethod(Class.java:1605) at MethodTrouble.main(MethodTrouble.java:12)

In this case, find() has no generic parameters, so the parameter types searched for by getMethod() must match exactly.

Tip: Always pass the upper bound of the parameterized type when searching for a method.

IllegalAccessException when Invoking a Method


An IllegalAccessException is thrown if an attempt is made to invoke a private or otherwise inaccessible method. The MethodTroubleAgain example shows a typical stack trace which results from trying to invoke a private method in an another class.
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; class AnotherClass { private void m() {} } public class MethodTroubleAgain { public static void main(String... args) { AnotherClass ac = new AnotherClass(); try { Class<?> c = ac.getClass(); Method m = c.getDeclaredMethod("m"); // m.setAccessible(true); // solution Object o = m.invoke(ac); // IllegalAccessException // production code should handle these exceptions more gracefully

53

} catch (NoSuchMethodException x) { x.printStackTrace(); } catch (InvocationTargetException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } } }

The stack trace for the exception thrown follows.


$ java MethodTroubleAgain java.lang.IllegalAccessException: Class MethodTroubleAgain can not access a member of class AnotherClass with modifiers "private" at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:6 5) at java.lang.reflect.Method.invoke(Method.java:588) at MethodTroubleAgain.main(MethodTroubleAgain.java:15)

Tip: An access restriction exists which prevents reflective invocation of methods which normally would not be accessible via direct invocation. (This includes---but is not limited to---private methods in a separate class and public methods in a separate private class.) However, Method is declared to extend AccessibleObject which provides the ability to suppress this check via AccessibleObject.setAccessible(). If it succeeds, then subsequent invocations of this method object will not fail due to this problem.

IllegalArgumentException from Method.invoke()


has been retrofitted to be a variable-arity method. This is an enormous convenience, however it can lead to unexpected behavior. The MethodTroubleToo example shows various ways in which Method.invoke() can produce confusing results.
Method.invoke() import java.lang.reflect.Method; public class MethodTroubleToo { public void ping() { System.out.format("PONG!%n"); } public static void main(String... args) { try { MethodTroubleToo mtt = new MethodTroubleToo(); Method m = MethodTroubleToo.class.getMethod("ping");

54

switch(Integer.parseInt(args[0])) { case 0: m.invoke(mtt); // works break; case 1: m.invoke(mtt, null); // works (expect compiler warning) break; case 2: Object arg2 = null; m.invoke(mtt, arg2); // IllegalArgumentException break; case 3: m.invoke(mtt, new Object[0]); // works break; case 4: Object arg4 = new Object[0]; m.invoke(mtt, arg4); // IllegalArgumentException break; default: System.out.format("Test not found%n"); } // production code should handle these exceptions more gracefully } catch (Exception x) { x.printStackTrace(); } } } $ java MethodTroubleToo 0 PONG!

Since all of the parameters of Method.invoke() are optional except for the first, they can be omitted when the method to be invoked has no parameters.
$ java MethodTroubleToo 1 PONG!

The code in this case generates this compiler warning because null is ambiguous.
$ javac MethodTroubleToo.java MethodTroubleToo.java:16: warning: non-varargs call of varargs method with inexact argument type for last parameter; cast to java.lang.Object for a varargs call cast to java.lang.Object[] for a non-varargs call and to suppress this warning m.invoke(mtt, null); // works (expect compiler warning) ^ 1 warning

55

It is not possible to determine whether null represents an empty array of arguments or a first argument of null.
$ java MethodTroubleToo 2 java.lang.IllegalArgumentException: wrong number of arguments at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAcc essorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingM ethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at MethodTroubleToo.main(MethodTroubleToo.java:21)

This fails despite the fact that the argument is null, because the type is a Object and ping() expects no arguments at all.
$ java MethodTroubleToo 3 PONG!

This works because new Object[0] creates an empty array, and to a varargs method, this is equivalent to not passing any of the optional arguments.
$ java MethodTroubleToo 4 java.lang.IllegalArgumentException: wrong number of arguments at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAcc essorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingM ethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at MethodTroubleToo.main(MethodTroubleToo.java:28)

Unlike the previous example, if the empty array is stored in an Object, then it is treated as an Object. This fails for the same reason that case 2 fails, ping() does not expect an argument.

Tip: When a method foo(Object... o) is declared the compiler will put all of the arguments passed to foo() in an array of type Object. The implementation of foo() is the same as if it were declared foo(Object[] o). Understanding this may help avoid the types of problems illustrated above.

56

InvocationTargetException when Invoked Method Fails


An InvocationTargetException wraps all exceptions (checked and unchecked) produced when a method object is invoked. The MethodTroubleReturns example shows how to retrieve the original exception thrown by the invoked method.
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class MethodTroubleReturns { private void drinkMe(int liters) { if (liters < 0) throw new IllegalArgumentException("I can't drink a negative amount of liquid"); } public static void main(String... args) { try { MethodTroubleReturns mtr = new MethodTroubleReturns(); Class<?> c = mtr.getClass(); Method m = c.getDeclaredMethod("drinkMe", int.class); m.invoke(mtr, -1); // production code should handle these exceptions more gracefully } catch (InvocationTargetException x) { Throwable cause = x.getCause(); System.err.format("drinkMe() failed: %s%n", cause.getMessage()); } catch (Exception x) { x.printStackTrace(); } } } $ java MethodTroubleReturns drinkMe() failed: I can't drink a negative amount of liquid

Tip: If an InvocationTargetException is thrown, the method was invoked. Diagnosis of the problem would be the same as if the method was called directly and threw the exception that is retrieved by getCause(). This exception does not indicate a problem with the reflection package or its usage.

Constructors

57

A constructor is used in the creation of an object that is an instance of a class. Typically it performs operations required to initialize the class before methods are invoked or fields are accessed. Constructors are never inherited. Similar to methods, reflection provides APIs to discover and retrieve the constructors of a class and obtain declaration information such as the modifiers, parameters, annotations, and thrown exceptions. New instances of classes may also be created using a specified constructor. The key classes used when working with constructors are Class and java.lang.reflect.Constructor. Common operations involving constructors are covered in the following sections: Finding Constructors illustrates how to retrieve constructors with specific parameters Retrieving and Parsing Constructor Modifiers shows how to obtain the modifiers of a constructor declaration and other information about the constructor Creating New Class Instances shows how to instantiate an instance of an object by invoking its constructor Troubleshooting describes common errors which may be encountered while finding or invoking constructors

Finding Constructors A constructor declaration includes the name, modifiers, parameters, and list of throwable exceptions. The java.lang.reflect.Constructor class provides a way to obtain this information. The ConstructorSift example illustrates how to search a class's declared constructors for one which has a parameter of a given type.
import java.lang.reflect.Constructor; import java.lang.reflect.Type; import static java.lang.System.out; public class ConstructorSift { public static void main(String... args) { try { Class<?> cArg = Class.forName(args[1]); Class<?> c = Class.forName(args[0]); Constructor[] allConstructors = c.getDeclaredConstructors(); for (Constructor ctor : allConstructors) {

58

Class<?>[] pType = ctor.getParameterTypes(); for (int i = 0; i < pType.length; i+ +) { if (pType[i].equals(cArg)) { out.format("%s%n", ctor.toGenericString()); Type[] gpType = ctor.getGenericParameterTypes(); for (int j = 0; j < gpType.length; j++) { char ch = (pType[j].equals(cArg) ? '*' : ' '); out.format("%7c%s[%d]: %s %n", ch, "GenericParameterType", j, gpType[j]); } break; } } } // production code should handle this exception more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } }

will consult the Signature Attribute in the class file if it's present. If the attribute isn't available, it falls back on Method.getParameterType() which was not changed by the introduction of generics. The other methods with name getGenericFoo() for some value of Foo in reflection are implemented similarly. The syntax for the returned values of Method.get*Types() is described in Class.getName().
Method.getGenericParameterTypes()

Here is the output for all constructors in java.util.Formatter which have a Locale argument.
$ java ConstructorSift java.util.Formatter java.util.Locale public java.util.Formatter(java.io.OutputStream,java.l ang.String,java.util.Locale) throws java.io.UnsupportedEncodingException GenericParameterType[0]: class java.io.OutputStream GenericParameterType[1]: class java.lang.String

59

*GenericParameterType[2]: class java.util.Locale public java.util.Formatter(java.lang.String,java.lang. String,java.util.Locale) throws java.io.FileNotFoundException,java.io.Unsupport edEncodingException GenericParameterType[0]: class java.lang.String GenericParameterType[1]: class java.lang.String *GenericParameterType[2]: class java.util.Locale public java.util.Formatter(java.lang.Appendable,java.u til.Locale) GenericParameterType[0]: interface java.lang.Appendable *GenericParameterType[1]: class java.util.Locale public java.util.Formatter(java.util.Locale) *GenericParameterType[0]: class java.util.Locale public java.util.Formatter(java.io.File,java.lang.Stri ng,java.util.Locale) throws java.io.FileNotFoundException,java.io.Unsupport edEncodingException GenericParameterType[0]: class java.io.File GenericParameterType[1]: class java.lang.String *GenericParameterType[2]: class java.util.Locale

The next example output illustrates how to search for a parameter of type char[] in String.
$ java ConstructorSift java.lang.String "[C" java.lang.String(int,int,char[]) GenericParameterType[0]: int GenericParameterType[1]: int *GenericParameterType[2]: class [C public java.lang.String(char[],int,int) *GenericParameterType[0]: class [C GenericParameterType[1]: int GenericParameterType[2]: int public java.lang.String(char[]) *GenericParameterType[0]: class [C

The syntax for expressing arrays of reference and primitive types acceptable to Class.forName() is described in Class.getName(). Note that the first listed constructor is package-private, not public. It is 60

returned because the example code uses Class.getDeclaredConstructors() rather than Class.getConstructors(), which returns only public constructors. This example shows that searching for arguments of variable arity (which have a variable number of parameters) requires use of array syntax:
$ java ConstructorSift java.lang.ProcessBuilder "[Ljava.lang.String;" public java.lang.ProcessBuilder(java.lang.String[]) *GenericParameterType[0]: class [Ljava.lang.String;

This is the actual declaration of the ProcessBuilder constructor in source code:


public ProcessBuilder(String... command)

The parameter is represented as a single-dimension array of type java.lang.String. This can be distinguished from a parameter that is explicitly an array of java.lang.String by invoking Constructor.isVarArgs(). The final example reports the output for a constructor which has been declared with a generic parameter type:
$ java ConstructorSift java.util.HashMap java.util.Map public java.util.HashMap(java.util.Map<? extends K, ? extends V>) *GenericParameterType[0]: java.util.Map<? extends K, ? extends V>

Exception types may be retrieved for constructors in a similar way as for methods. See the MethodSpy example described in Obtaining Method Type Information section for further details.

Retrieving and Parsing Constructor Modifiers Because of the role of constructors in the language, fewer modifiers are meaningful than for methods:

Access modifiers: public, protected, and private Annotations

61

The ConstructorAccess example searches for constructors in a given class with the specified access modifier. It also displays whether the constructor is synthetic (compiler-generated) or of variable arity.
import import import import java.lang.reflect.Constructor; java.lang.reflect.Modifier; java.lang.reflect.Type; static java.lang.System.out;

public class ConstructorAccess { public static void main(String... args) { try { Class<?> c = Class.forName(args[0]); Constructor[] allConstructors = c.getDeclaredConstructors(); for (Constructor ctor : allConstructors) { int searchMod = modifierFromString(args[1]); int mods = accessModifiers(ctor.getModifiers()); if (searchMod == mods) { out.format("%s%n", ctor.toGenericString()); out.format(" [ synthetic=%-5b var_args=%-5b ]%n", ctor.isSynthetic(), ctor.isVarArgs()); } } // production code should handle this exception more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } private static int accessModifiers(int m) { return m & (Modifier.PUBLIC | Modifier.PRIVATE | Modifier.PROTECTED); } private static int modifierFromString(String s) { if ("public".equals(s)) Modifier.PUBLIC; else if ("protected".equals(s)) Modifier.PROTECTED; else if ("private".equals(s)) Modifier.PRIVATE; else if ("package-private".equals(s)) 0; else return -1; }

return return return return

62

There is not an explicit Modifier constant which corresponds to "package-private" access, so it is necessary to check for the absence of all three access modifiers to identify a package-private constructor. This output shows the private constructors in java.io.File:
$ java ConstructorAccess java.io.File private private java.io.File(java.lang.String,int) [ synthetic=false var_args=false ] private java.io.File(java.lang.String,java.io.File) [ synthetic=false var_args=false ]

Synthetic constructors are rare; however the SyntheticConstructor example illustrates a typical situation where this may occur:
public class SyntheticConstructor { private SyntheticConstructor() {} class Inner { // Compiler will generate a synthetic constructor since // SyntheticConstructor() is private. Inner() { new SyntheticConstructor(); } } } $ java ConstructorAccess SyntheticConstructor package-private SyntheticConstructor(SyntheticConstructor$1) [ synthetic=true var_args=false ]

Since the inner class's constructor references the private constructor of the enclosing class, the compiler must generate a package-private constructor. The parameter type SyntheticConstructor$1 is arbitrary and dependent on the compiler implementation. Code which depends on the presence of any synthetic or non-public class members may not be portable. Constructors implement java.lang.reflect.AnnotatedElement, which provides methods to retrieve runtime annotations with java.lang.annotation.RetentionPolicy.RUNTIME. For an example of obtaining annotations see the Examining Class Modifiers and Types section. Creating New Class Instances There are two reflective methods for creating instances of classes: java.lang.reflect.Constructor.newInstance() and

63

Class.newInstance().

The former is preferred and is thus used in these

examples because:
Class.newInstance() can only invoke the zero-argument constructor, while Constructor.newInstance() may invoke any constructor, regardless of the number of parameters. Class.newInstance() throws any exception thrown by the constructor, regardless of whether it is checked or unchecked. InvocationTargetException. Class.newInstance() requires that the constructor be visible; Constructor.newInstance() may invoke private constructors under certain circumstances.

Sometimes it may be desirable to retrieve internal state from an object which is only set after construction. Consider a scenario where it is necessary to obtain the internal character set used by java.io.Console. (The Console character set is stored in an private field and is not necessarily the same as the Java virtual machine default character set returned by java.nio.charset.Charset.defaultCharset()). The ConsoleCharset example shows how this might be achieved:
import java.io.Console; import java.nio.charset.Charset; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import static java.lang.System.out; public class ConsoleCharset { public static void main(String... args) { Constructor[] ctors = Console.class.getDeclaredConstructors(); Constructor ctor = null; for (int i = 0; i < ctors.length; i++) { ctor = ctors[i]; if (ctor.getGenericParameterTypes().length == 0) break; } try { ctor.setAccessible(true); Console c = (Console)ctor.newInstance(); Field f = c.getClass().getDeclaredField("cs"); f.setAccessible(true); out.format("Console charset : %s%n", f.get(c)); out.format("Charset.defaultCharset(): %s%n",

64

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

Note: Class.newInstance() will only succeed if the constructor is has zero arguments and is already accessible. Otherwise, it is necessary to use Constructor.newInstance() as in the above example.

Example output for a Unix system:


$ java ConsoleCharset Console charset : Charset.defaultCharset() : ISO-8859-1 ISO-8859-1

Example output for a Windows system:


C:\> java ConsoleCharset Console charset : Charset.defaultCharset() : IBM437 windows-1252

Another common application of Constructor.newInstance() is to invoke constructors which take arguments. The RestoreAliases example finds a specific single-argument constructor and invokes it:
import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import java.util.Set; import static java.lang.System.out; class EmailAliases { private Set<String> aliases;

65

private EmailAliases(HashMap<String, String> h) { aliases = h.keySet(); } public void printKeys() { out.format("Mail keys:%n"); for (String k : aliases) out.format(" %s%n", k); } } public class RestoreAliases { private static Map<String, String> defaultAliases = new HashMap<String, String>(); static { defaultAliases.put("Duke", "duke@i-lovejava"); defaultAliases.put("Fang", "fang@eviljealous-twin"); } public static void main(String... args) { try { Constructor ctor = EmailAliases.class.getDeclaredConstructor(HashM ap.class); ctor.setAccessible(true); EmailAliases email = (EmailAliases)ctor.newInstance(defaultAliases); email.printKeys(); // production code should handle these exceptions more gracefully } catch (InstantiationException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } catch (InvocationTargetException x) { x.printStackTrace(); } catch (NoSuchMethodException x) { x.printStackTrace(); } } }

This example uses Class.getDeclaredConstructor() to find the constructor with a single argument of type java.util.HashMap. Note that it is sufficient to pass HashMap.class since the parameter to any get*Constructor() method requires a class only for type purposes. Due to type erasure, the following expression evaluates to true:
HashMap.class == defaultAliases.getClass()

66

The example then creates a new instance of the class using this constructor with Constructor.newInstance().
$ java RestoreAliases Mail keys: Duke Fang

Troubleshooting The following problems are sometimes encountered by developers when trying to invoke constructors via reflection.

InstantiationException Due to Missing Zero-Argument Constructor


The ConstructorTrouble example illustrates what happens when code attempts to create a new instance of a class using Class.newInstance() and there is no accessible zero-argument constructor:
public class ConstructorTrouble { private ConstructorTrouble(int i) {} public static void main(String... args){ try { Class<?> c = Class.forName("ConstructorTrouble"); Object o = c.newInstance(); // InstantiationException // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } catch (InstantiationException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } } } $ java ConstructorTrouble java.lang.InstantiationException: ConstructorTrouble at java.lang.Class.newInstance0(Class.java:340) at java.lang.Class.newInstance(Class.java:308)

67

at ConstructorTrouble.main(ConstructorTrouble.java :7)

Tip: There a number of different reasons an InstantiationException can occur. In this case, the problem is that the presence of the constructor with an int argument prevents the compiler from generating the default (or zero-argument) constructor and there is no explicit zeroargument constructor in the code. Remember that Class.newInstance() behaves very much like the new keyword and will fail whenever new would fail.

Class.newInstance() Throws Unexpected Exception


The ConstructorTroubleToo example shows an unresolvable problem in Class.newInstance(). Namely, it propagates any exception checked or unchecked thrown by the constructor.
import java.lang.reflect.InvocationTargetException; import static java.lang.System.err; public class ConstructorTroubleToo { public ConstructorTroubleToo() { throw new RuntimeException("exception in constructor"); } public static void main(String... args) { try { Class<?> c = Class.forName("ConstructorTroubleToo"); // Method propagetes any exception thrown by the constructor // (including checked exceptions). if (args.length > 0 && args[0].equals("class")) { Object o = c.newInstance(); } else { Object o = c.getConstructor().newInstance(); } // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } catch (InstantiationException x) {

68

x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } catch (NoSuchMethodException x) { x.printStackTrace(); } catch (InvocationTargetException x) { x.printStackTrace(); err.format("%n%nCaught exception: %s%n", x.getCause()); } } } $ java ConstructorTroubleToo class Exception in thread "main" java.lang.RuntimeException: exception in constructor at ConstructorTroubleToo.<init>(ConstructorTrouble Too.java:6) at sun.reflect.NativeConstructorAccessorImpl.newIn stance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newIn stance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.n ewInstance(DelegatingConstructorAccessorImpl.ja va:27) at java.lang.reflect.Constructor.newInstance(Const ructor.java:513) at java.lang.Class.newInstance0(Class.java:355) at java.lang.Class.newInstance(Class.java:308) at ConstructorTroubleToo.main(ConstructorTroubleTo o.java:15)

This situation is unique to reflection. Normally, it is impossible to write code which ignores a checked exception because it would not compile. It is possible to wrap any exception thrown by a constructor by using Constructor.newInstance() rather than Class.newInstance().
$ java ConstructorTroubleToo java.lang.reflect.InvocationTargetException at sun.reflect.NativeConstructorAccessorImpl.newIn stance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newIn stance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.n

69

ewInstance(DelegatingConstructorAccessorImpl.ja va:27) at java.lang.reflect.Constructor.newInstance(Const ructor.java:513) at ConstructorTroubleToo.main(ConstructorTroubleTo o.java:17) Caused by: java.lang.RuntimeException: exception in constructor at ConstructorTroubleToo.<init>(ConstructorTrouble Too.java:6) ... 5 more Caught exception: java.lang.RuntimeException: exception in constructor

If an InvocationTargetException is thrown, the method was invoked. Diagnosis of the problem would be the same as if the constructor was called directly and threw the exception that is retrieved by InvocationTargetException.getCause(). This exception does not indicate a problem with the reflection package or its usage.

Tip: It is preferable to use Constructor.newInstance() over Class.newInstance() because the former API permits examination and handling of arbitrary exceptions thrown by constructors.

Problems Locating or Invoking the Correct Constructor


The ConstructorTroubleAgain class illustrates various ways in which incorrect code can fail to locate or invoke the expected constructor.
import java.lang.reflect.InvocationTargetException; import static java.lang.System.out; public class ConstructorTroubleAgain { public ConstructorTroubleAgain() {} public ConstructorTroubleAgain(Integer i) {} public ConstructorTroubleAgain(Object o) { out.format("Constructor passed Object%n"); } public ConstructorTroubleAgain(String s) {

70

out.format("Constructor passed String%n"); } public static void main(String... args){ String argType = (args.length == 0 ? "" : args[0]); try { Class<?> c = Class.forName("ConstructorTroubleAgain"); if ("".equals(argType)) { // IllegalArgumentException: wrong number of arguments Object o = c.getConstructor().newInstance("foo"); } else if ("int".equals(argType)) { // NoSuchMethodException - looking for int, have Integer Object o = c.getConstructor(int.class); } else if ("Object".equals(argType)) { // newInstance() does not perform method resolution Object o = c.getConstructor(Object.class).newInstance("foo "); } else { assert false; } // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } catch (NoSuchMethodException x) { x.printStackTrace(); } catch (InvocationTargetException x) { x.printStackTrace(); } catch (InstantiationException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } } } $ java ConstructorTroubleAgain Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments at sun.reflect.NativeConstructorAccessorImpl.newIn stance0(Native Method) at sun.reflect.NativeConstructorAccessorImpl.newIn stance(NativeConstructorAccessorImpl.java:39) at sun.reflect.DelegatingConstructorAccessorImpl.n

71

ewInstance(DelegatingConstructorAccessorImpl.ja va:27) at java.lang.reflect.Constructor.newInstance(Const ructor.java:513) at ConstructorTroubleAgain.main(ConstructorTrouble Again.java:23)

An IllegalArgumentException is thrown because the zero-argument constructor was requested and an attempt was made to pass an argument. The same exception would be thrown if the constructor was passed an argument of the wrong type.
$ java ConstructorTroubleAgain int java.lang.NoSuchMethodException: ConstructorTroubleAgain.<init>(int) at java.lang.Class.getConstructor0(Class.java:2706) at java.lang.Class.getConstructor(Class.java:1657) at ConstructorTroubleAgain.main(ConstructorTrouble Again.java:26)

This exception may occur if the developer mistakenly believes that reflection will autobox or unbox types. Boxing (conversion of a primitive to a reference type) occurs only during compilation. There is no opportunity in reflection for this operation to occur, so the specific type must be used when locating a constructor.
$ java ConstructorTroubleAgain Object Constructor passed Object

Here, it might be expected that the constructor taking a String argument would be invoked since newInstance() was invoked with the more specific String type. However it is too late! The constructor which was found is already the constructor with an Object argument. newInstance() makes no attempt to do method resolution; it simply operates on the existing constructor object.

Tip: An important difference between new and Constructor.newInstance() is that new performs method argument type checking, boxing, and method resolution. None of these occur in reflection, where explicit choices must be made.

72

IllegalAccessException When Attempting to Invoke an Inaccessible Constructor


An IllegalAccessException may be thrown if an attempt is made to invoke a private or otherwise inaccessible constructor. The ConstructorTroubleAccess example illustrates the resulting stack trace.
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; class Deny { private Deny() { System.out.format("Deny constructor%n"); } } public class ConstructorTroubleAccess { public static void main(String... args) { try { Constructor c = Deny.class.getDeclaredConstructor(); // c.setAccessible(true); // solution c.newInstance(); // production code should handle these exceptions more gracefully } catch (InvocationTargetException x) { x.printStackTrace(); } catch (NoSuchMethodException x) { x.printStackTrace(); } catch (InstantiationException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } } } $ java ConstructorTroubleAccess java.lang.IllegalAccessException: Class ConstructorTroubleAccess can not access a member of class Deny with modifiers "private" at sun.reflect.Reflection.ensureMemberAccess(Refle ction.java:65) at java.lang.reflect.Constructor.newInstance(Const ructor.java:505) at ConstructorTroubleAccess.main(ConstructorTroubl eAccess.java:15)

73

Tip: An access restriction exists which prevents reflective invocation of constructors which normally would not be accessible via direct invocation. (This includes---but is not limited to---private constructors in a separate class and public constructors in a separate private class.) However, Constructor is declared to extend AccessibleObject which provides the ability to suppress this check via AccessibleObject.setAccessible(). Lesson: Arrays and Enumerated Types From the Java virtual machine's perspective, arrays and enumerated types (or enums) are just classes. Many of the methods in Class may be used on them. Reflection provides a few specific APIs for arrays and enums. This lesson uses a series of code samples to describe how to distinguish each of these objects from other classes and operate on them. Various errors are also be examined.

Arrays
Arrays have a component type and a length (which is not part of the type). Arrays may be maniuplated either in their entirety or component by component. Reflection provides the java.lang.reflect.Array class for the latter purpose. Identifying Array Types describes how to determine if a class member is a field of array type Creating New Arrays illustrates how to create new instances of arrays with simple and complex component types Getting and Setting Arrays and Their Components shows how to access fields of type array and individually access array elements Troubleshooting covers common errors and programming misconceptions

Enumerated Types
Enums are treated very much like ordinary classes in reflection code. Class.isEnum() tells whether a Class represents and enum. Class.getEnumConstants() retrieves the enum constants defined in an enum. java.lang.reflect.Field.isEnumConstant() indicates whether a field is an enumerated type. Examining Enums illustrates how to retrieve an enum's constants and any other fields, constructors, and methods

74

Getting and Setting Fields with Enum Types shows how to set and get fields with an enum constant value Troubleshooting describes common errors associated with enums

Arrays An array is an object of reference type which contains a fixed number of components of the same type; the length of an array is immutable. Creating an instance of an array requires knowledge of the length and component type. Each component may be a primitive type (e.g. byte, int, or double), a reference type (e.g. String, Object, or java.nio.CharBuffer), or an array. Multi-dimensional arrays are really just arrays which contain components of array type. Arrays are implemented in the Java virtual machine. The only methods on arrays are those inherited from Object. The length of an array is not part of its type; arrays have a length field which is accessible via java.lang.reflect.Array.getLength(). Reflection provides methods for accessing array types and array component types, creating new arrays, and retrieving and setting array component values. The following sections include examples of common operations on arrays: Identifying Array Types describes how to determine if a class member is a field of array type Creating New Arrays illustrates how to create new instances of arrays with simple and complex component types Getting and Setting Arrays and Their Components shows how to access fields of type array and individually access array elements Troubleshooting covers common errors and programming misconceptions

All of these operations are supported via static methods in java.lang.reflect.Array.

Identifying Array Types

75

Array types may be identified by invoking Class.isArray(). To obtain a Class use one of the methods described in Retrieving Class Objects section of this trail. The ArrayFind example identifies the fields in the named class that are of array type and reports the component type for each of them.
import java.lang.reflect.Field; import java.lang.reflect.Type; import static java.lang.System.out; public class ArrayFind { public static void main(String... args) { boolean found = false; try { Class<?> cls = Class.forName(args[0]); Field[] flds = cls.getDeclaredFields(); for (Field f : flds) { Class<?> c = f.getType(); if (c.isArray()) { found = true; out.format("%s%n" + " Field: %s%n" + " Type: %s%n" + " Component Type: %s%n", f, f.getName(), c, c.getComponentType()); } } if (!found) { out.format("No array fields%n"); } // production code should handle this exception more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } } }

The syntax for the returned value of Class.get*Type() is described in Class.getName(). The number of '[' characters at the beginning of the type name indicates the number of dimensions (i.e. depth of nesting) of the array. Samples of the output follows. User input is in italics. An array of primitive type byte:

76

$ java ArrayFind java.nio.ByteBuffer final byte[] java.nio.ByteBuffer.hb Field: hb Type: class [B Component Type: byte

An array of reference type StackTraceElement:


$ java ArrayFind java.lang.Throwable private java.lang.StackTraceElement[] java.lang.Throwable.stackTrace Field: stackTrace Type: class [Ljava.lang.StackTraceElement; Component Type: class java.lang.StackTraceElement predefined is a one-dimensional array of reference type java.awt.Cursor and cursorProperties is a two-dimensional reference type String: $ java ArrayFind java.awt.Cursor protected static java.awt.Cursor[] java.awt.Cursor.predefined Field: predefined Type: class [Ljava.awt.Cursor; Component Type: class java.awt.Cursor static final java.lang.String[][] java.awt.Cursor.cursorProperties Field: cursorProperties Type: class [[Ljava.lang.String; Component Type: class [Ljava.lang.String;

array of

Creating New Arrays Just as in non-reflective code, reflection supports the ability to dynamically create arrays of arbitrary type and dimensions via java.lang.reflect.Array.newInstance(). Consider ArrayCreator, a basic interpreter capable of dynamically creating arrays. The syntax that will be parsed is as follows:
fully_qualified_class_name variable_name[] = { val1, val2, val3, ... }

Assume that the fully_qualified_class_name represents a class that has a constructor with a single String argument. The dimensions of the array are determined by the number of values provided. The following example will construct an instance of an array of fully_qualified_class_name and populate its values with instances 77

given by val1, val2, etc. (This example assumes familiarity with Class.getConstructor() and java.lang.reflect.Constructor.newInstance(). For a discussion of the reflection APIs for Constructor see the Creating New Class Instances section of this trail.)
import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.regex.Pattern; import java.util.regex.Matcher; import java.util.Arrays; import static java.lang.System.out; public class ArrayCreator { private static String s = "java.math.BigInteger bi[] = { 123, 234, 345 }"; private static Pattern p = Pattern.compile("^\\s*(\\S+)\\s*\\w+\\[\\].*\\ {\\s*([^}]+)\\s*\\}"); public static void main(String... args) { Matcher m = p.matcher(s); if (m.find()) { String cName = m.group(1); String[] cVals = m.group(2).split("[\\s,]+"); int n = cVals.length; try { Class<?> c = Class.forName(cName); Object o = Array.newInstance(c, n); for (int i = 0; i < n; i++) { String v = cVals[i]; Constructor ctor = c.getConstructor(String.class); Object val = ctor.newInstance(v); Array.set(o, i, val); } Object[] oo = (Object[])o; out.format("%s[] = %s%n", cName, Arrays.toString(oo)); // production code should handle these exceptions more gracefully } catch (ClassNotFoundException x) { x.printStackTrace(); } catch (NoSuchMethodException x) {

78

x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } catch (InstantiationException x) { x.printStackTrace(); } catch (InvocationTargetException x) { } } } x.printStackTrace();

} $ java ArrayCreator java.math.BigInteger [] = [123, 234, 345]

The above example shows one case where it may be desirable to create an array via reflection; namely if the component type is not known until runtime. In this case, the code uses Class.forName() to get a class for the desired component type and then calls a specific constructor to initialize each component of the array before setting the corresponding array value.

Getting and Setting Arrays and Their Components Just as in non-reflective code, an array field may be set or retrieved in its entirety or component by component. To set the entire array at once, use java.lang.reflect.Field.set(Object obj, Object value). To retrieve the entire array, use Field.get(Object). Individual components can be set or retrieved using methods in java.lang.reflect.Array. provides methods of the form setFoo() and getFoo() for setting and getting components of any primitive type. For example, the component of an int array may be set with Array.setInt(Object array, int index, int value) and may be retrieved with Array.getInt(Object array, int index).
Array

These methods support automatic widening of data types. Therefore, Array.getShort() may be used to set the values of an int array since a 16-bit short may be widened to a 32-bit int without loss of data; on the other hand, invoking Array.setLong() on an array of int will cause an IllegalArgumentException to be thrown because a 64-bit long can not be narrowed to for storage in a 32-bit int with out loss of information. This is true regardless of whether the actual values being passed could be accurately represented in the target data type. The Java Language Specification, Third Edition, sections 5.1.2 and 5.1.3 contains a complete discussion of widening and narrowing conversions.

79

The components of arrays of reference types (including arrays of arrays) are set and retrieved using Array.set(Object array, int index, int value)and Array.get(Object array, int index).

Setting a Field of Type Array


The GrowBufferedReader example illustrates how to replace the value of a field of type array. In this case, the code replaces the backing array for a java.io.BufferedReader with a larger one. (This assumes that the creation of the original BufferedReader is in code that is not modifiable; otherwise, it would be trivial to simply use the alternate constructor BufferedReader(java.io.Reader in, int size) which accepts an input buffer size.)
import import import import import import import java.io.BufferedReader; java.io.CharArrayReader; java.io.FileNotFoundException; java.io.IOException; java.lang.reflect.Field; java.util.Arrays; static java.lang.System.out;

public class GrowBufferedReader { private static final int srcBufSize = 10 * 1024; private static char[] src = new char[srcBufSize]; static { src[srcBufSize - 1] = 'x'; } private static CharArrayReader car = new CharArrayReader(src); public static void main(String... args) { try { BufferedReader br = new BufferedReader(car); Class<?> c = br.getClass(); Field f = c.getDeclaredField("cb"); // cb is a private field f.setAccessible(true); char[] cbVal = char[].class.cast(f.get(br)); char[] newVal = Arrays.copyOf(cbVal, cbVal.length * 2); if (args.length > 0 && args[0].equals("grow")) f.set(br, newVal);

80

for (int i = 0; i < srcBufSize; i++) br.read(); // see if the new backing array is being used if (newVal[srcBufSize - 1] == src[srcBufSize - 1]) out.format("Using new backing array, size=%d%n", newVal.length); else out.format("Using original backing array, size=%d%n", cbVal.length); // production code should handle these exceptions more gracefully } catch (FileNotFoundException x) { x.printStackTrace(); } catch (NoSuchFieldException x) { x.printStackTrace(); } catch (IllegalAccessException x) { x.printStackTrace(); } catch (IOException x) { x.printStackTrace(); } } } $ java GrowBufferedReader grow Using new backing array, size=16384 $ java GrowBufferedReader Using original backing array, size=8192

Note that the above example makes use of the array utility method java.util.Arrays.copyOf). java.util.Arrays contains many methods which are convenient when operating on arrays.

Accessing Elements of a Multidimensional Array


Multi-dimensional arrays are simply nested arrays. A two-dimensional array is an array of arrays. A three-dimensional array is an array of twodimensional arrays, and so on. The CreateMatrix example illustrates how to create and initialize a multi-dimensional array using reflection.
import java.lang.reflect.Array; import static java.lang.System.out; public class CreateMatrix { public static void main(String... args) { Object matrix = Array.newInstance(int.class, 2, 2); Object row0 = Array.get(matrix, 0); Object row1 = Array.get(matrix, 1); Array.setInt(row0, 0, 1);

81

Array.setInt(row0, 1, 2); Array.setInt(row1, 0, 3); Array.setInt(row1, 1, 4); for (int i = 0; i < 2; i++) for (int j = 0; j < 2; j++) out.format("matrix[%d][%d] = %d %n", i, j, ((int[][])matrix)[i][j]); } } $ java CreateMatrix matrix[0][0] = 1 matrix[0][1] = 2 matrix[1][0] = 3 matrix[1][1] = 4

The same result could be obtained by using the following code fragment:
Object matrix = Array.newInstance(int.class, 2); Object row0 = Array.newInstance(int.class, 2); Object row1 = Array.newInstance(int.class, 2); Array.setInt(row0, Array.setInt(row0, Array.setInt(row1, Array.setInt(row1, 0, 1, 0, 1, 1); 2); 3); 4);

Array.set(matrix, 0, row0); Array.set(matrix, 1, row1);

The variable argument Array.newInstance(Class<?> componentType, int... dimensions) provides a convenient way to create multidimensional arrays, but the components still need to initialized using the principle that that multi-dimensional arrays are nested arrays. (Reflection does not provide multiple indexed get/set methods for this purpose.) Troubleshooting The following examples show typical errors which may occur when operating on arrays.

IllegalArgumentException due to Inconvertible Types


The ArrayTroubleAgain example will generate an IllegalArgumentException. Array.setInt() is invoked to set a component that is of the reference type Integer with a value of primitive type int. In the non-reflection equivalent ary[0] = 1, the compiler would convert (or box) the value 1 to a reference type as new Integer(1) so that its type checking will accept the statement. When using reflection, type checking only occurs at runtime so there is no opportunity to box the value. 82

import java.lang.reflect.Array; import static java.lang.System.err; public class ArrayTroubleAgain { public static void main(String... args) { Integer[] ary = new Integer[2]; try { Array.setInt(ary, 0, 1); // IllegalArgumentException // production code should handle these exceptions more gracefully } catch (IllegalArgumentException x) { err.format("Unable to box%n"); } catch (ArrayIndexOutOfBoundsException x) { x.printStackTrace(); } } } $ java ArrayTroubleAgain Unable to box

To eliminate this exception, the problematic line should be replaced by the following invocation of Array.set(Object array, int index, Object value):
Array.set(ary, 0, new Integer(1));

Tip: When using reflection to set or get an array component, the compiler does not have an opportunity to perform boxing. It can only convert types that are related as described by the specification for Class.isAssignableFrom(). The example is expected to fail because isAssignableFrom() will return false in this test which can be used programmatically to verify whether a particular conversion is possible:
Integer.class.isAssignableFrom(int. class) == false

Similarly, automatic conversion from primitive to reference type is also impossible in reflection.
int.class.isAssignableFrom(Integer. class) == false

ArrayIndexOutOfBoundsException for Empty Arrays

83

The ArrayTrouble example illustrates an error which will occur if an attempt is made to access the elements of an array of zero length:
import java.lang.reflect.Array; import static java.lang.System.out; public class ArrayTrouble { public static void main(String... args) { Object o = Array.newInstance(int.class, 0); int[] i = (int[])o; int[] j = new int[0]; out.format("i.length = %d, j.length = %d, args.length = %d%n", i.length, j.length, args.length); Array.getInt(o, 0); // ArrayIndexOutOfBoundsException } } $ java ArrayTrouble i.length = 0, j.length = 0, args.length = 0 Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException at java.lang.reflect.Array.getInt(Native Method) at ArrayTrouble.main(ArrayTrouble.java:11)

Tip: It is possible to have arrays with no elements (empty arrays). There are only a few cases in common code where they are seen but they can occur in reflection inadvertently. Of course, it is not possible to set/get the values of an empty array because an ArrayIndexOutOfBoundsException will be thrown.

IllegalArgumentException if Narrowing is Attempted


The ArrayTroubleToo example contains code which fails because it attempts perform an operation which could potentially lose data:
import java.lang.reflect.Array; import static java.lang.System.out; public class ArrayTroubleToo { public static void main(String... args) { Object o = new int[2];

84

Array.setShort(o, 0, (short)2); // widening, succeeds Array.setLong(o, 1, 2L); // narrowing, fails } } $ java ArrayTroubleToo Exception in thread "main" java.lang.IllegalArgumentException: argument type mismatch at java.lang.reflect.Array.setLong(Native Method) at ArrayTroubleToo.main(ArrayTroubleToo.java:9)

Tip: The Array.set*() and Array.get*() methods will perform automatic widening conversion but will throw an IllegalArgumentException if a narrowing conversion is attempted. For complete discussion of widening and narrowing conversions, see The Java Language Specification, Third Edition, sections 5.1.2 and 5.1.3 respectively.

Enumerated Types An enum is a language construct that is used to define type-safe enumerations which can be used when a fixed set of named values is desired. All enums implicitly extend java.lang.Enum. Enums may contain one or more enum constants, which define unique instances of the enum type. An enum declaration defines an enum type which is very similar to a class in that it may have members such as fields, methods, and constructors (with some restrictions). Since enums are classes, reflection has no need to define an explicit java.lang.reflect.Enum class. The only Reflection APIs that are specific to enums are Class.isEnum(), Class.getEnumConstants(), and java.lang.reflect.Field.isEnumConstant(). Most reflective operations involving enums are the same as any other class or member. For example, enum constants are implemented as public static final fields on the enum. The following sections show how to use Class and java.lang.reflect.Field with enums. Examining Enums illustrates how to retrieve an enum's constants and any other fields, constructors, and methods Getting and Setting Fields with Enum Types shows how to set and get fields with an enum constant value

85

Troubleshooting describes common errors associated with

enums For an introduction to enums, see the Enum Types section of the Java Tutorial Trail Learning the Java Language.

Examining Enums Reflection provides three enum-specific APIs:


Class.isEnum()

Indicates whether this class represents an enum type


Class.getEnumConstants()

Retrieves the list of enum constants defined by the enum in the order they're declared
java.lang.reflect.Field.isEnumConstant()

Indicates whether this field represents an element of an enumerated type Sometimes it is necessary to dynamically retrieve the list of enum constants; in non-reflective code this is accomplished by invoking the implicitly declared static method values() on the enum. If an instance of an enum type is not available the only way to get a list of the possible values is to invoke Class.getEnumConstants() since it is impossible to instantiate an enum type. Given a fully qualified name, the EnumConstants example shows how to retrieve an ordered list of constants in an enum using 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("Enum name: %s%nEnum constants: %s%n", c.getName(), Arrays.asList(c.getEnumConstants())); if (c == Eon.class) out.format(" Eon.values(): %s%n",

86

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

Samples of the output follows. User input is in italics.


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

This example also shows that value returned by Class.getEnumConstants() is identical to the value returned by invoking values() on an enum type.
$ java EnumConstants Enum name: Eon Enum constants: [HADEAN, ARCHAEAN, PROTEROZOIC, PHANEROZOIC] Eon.values(): [HADEAN, ARCHAEAN, PROTEROZOIC, PHANEROZOIC]

Since enums are classes, other information may be obtained using the same Reflection APIs described in the Fields, Methods, and Constructors sections of this trail. The EnumSpy code illustrates how to use these APIs to get additional information about the enum's declaration. The example uses Class.isEnum() to restrict the set of classes examined. It also uses Field.isEnumConstant() to distinguish enum constants from other fields in the enum declaration (not all fields are enum constants).
import import import import import import import java.lang.reflect.Constructor; java.lang.reflect.Field; java.lang.reflect.Method; java.lang.reflect.Member; java.util.List; java.util.ArrayList; static java.lang.System.out;

public class EnumSpy {

87

private static final String fmt = " %s %s%n";

%11s:

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

88

} 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.valueOf(ja va.lang.String) Method: public static java.lang.annotation.RetentionPolicy[] java.lang.annotation.RetentionPolicy.values()

The output shows that declaration of only contains the three enum constants. The enum constants are exposed as public static final fields. The field, constructor, and methods are compiler generated. The $VALUES field is related to the implementation of the values() method.
java.lang.annotation.RetentionPolicy

Note: For various reasons, including support for evolution of the enum type, the declaration order of enum constants is important. Class.getFields() and Class.getDeclaredFields() do not make any guarantee that the order of the returned values matches the order in the declaring source code. If ordering is required by an application, use Class.getEnumConstants().

The output for java.util.concurrent.TimeUnit shows that much more complicated enums are possible. This class includes several methods as 89

well as additional fields declared static final which are not enum constants.
$ java EnumSpy java.util.concurrent.TimeUnit Class: class java.util.concurrent.TimeUnit Constant: public static final java.util.concurrent.TimeUnit java.util.concurrent.TimeUnit.NANOSECONDS Constant: public static final java.util.concurrent.TimeUnit java.util.concurrent.TimeUnit.MICROSECONDS Constant: public static final java.util.concurrent.TimeUnit java.util.concurrent.TimeUnit.MILLISECONDS Constant: public static final java.util.concurrent.TimeUnit java.util.concurrent.TimeUnit.SECONDS Constant: public static final java.util.concurrent.TimeUnit java.util.concurrent.TimeUnit.MINUTES Constant: public static final java.util.concurrent.TimeUnit java.util.concurrent.TimeUnit.HOURS Constant: public static final java.util.concurrent.TimeUnit java.util.concurrent.TimeUnit.DAYS Field: static final long java.util.concurrent.TimeUnit.C0 Field: static final long java.util.concurrent.TimeUnit.C1 Field: static final long java.util.concurrent.TimeUnit.C2 Field: static final long java.util.concurrent.TimeUnit.C3 Field: static final long java.util.concurrent.TimeUnit.C4 Field: static final long java.util.concurrent.TimeUnit.C5 Field: static final long java.util.concurrent.TimeUnit.C6 Field: static final long java.util.concurrent.TimeUnit.MAX Field: private static final java.util.concurrent.TimeUnit[] java.util.concurrent.TimeUnit. [ synthetic ] Constructor: private java.util.concurrent.TimeUnit() Constructor: java.util.concurrent.TimeUnit(java.lang.String, int,java.util.concurrent.TimeUnit) [ synthetic ] Method: public static java.util.concurrent.TimeUnit java.util.concurrent.TimeUnit.valueOf(java.lang .String)

90

Method: public static java.util.concurrent.TimeUnit[] java.util.concurrent.TimeUnit.values() Method: public void java.util.concurrent.TimeUnit.sleep(long) throws java.lang.InterruptedException Method: public long java.util.concurrent.TimeUnit.toNanos(long) Method: public long java.util.concurrent.TimeUnit.convert(long,java .util.concurrent.TimeUnit) Method: abstract int java.util.concurrent.TimeUnit.excessNanos(long, long) Method: public void java.util.concurrent.TimeUnit.timedJoin(java.la ng.Thread,long) throws java.lang.InterruptedException Method: public void java.util.concurrent.TimeUnit.timedWait(java.la ng.Object,long) throws java.lang.InterruptedException Method: public long java.util.concurrent.TimeUnit.toDays(long) Method: public long java.util.concurrent.TimeUnit.toHours(long) Method: public long java.util.concurrent.TimeUnit.toMicros(long) Method: public long java.util.concurrent.TimeUnit.toMillis(long) Method: public long java.util.concurrent.TimeUnit.toMinutes(long) Method: public long java.util.concurrent.TimeUnit.toSeconds(long) Method: static long java.util.concurrent.TimeUnit.x(long,long,long)

Getting and Setting Fields with Enum Types Fields which store enums are set and retrieved as any other reference type, using Field.set() and Field.get(). For more information on accessing fields, see the Fields section of this trail. 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.

91

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: %n", f.get(svr)); }

%s

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

Since the enum constants are singletons, the == and != operators may be used to compare enum constants of the same type.
$ java SetTrace OFF Original trace level: $ java SetTrace DEBUG Original trace level: New trace level: OFF OFF DEBUG

Troubleshooting 92

The following examples show problems which may be encountered when using enumerated types. 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

93

at java.lang.reflect.Constructor.newInstance(Const ructor.java:511) at EnumTrouble.main(EnumTrouble.java:22)

Tip: It is a compile-time error to attempt to explicitly instantiate an enum because that would prevent the defined enum constants from being unique. This restriction is also enforced in reflective code. Code which attempts to instantiate classes using their default constructors should invoke Class.isEnum() first to determine if the class is an enum.

IllegalArgumentException when Setting a Field with an Incompatible Enum Type


Fields storing enums set with the appropriate enum type. (Actually, fields of any type must be set with compatible types.) The EnumTroubleToo example produces the expected error.
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

94

Exception in thread "main" java.lang.IllegalArgumentException: Can not set E0 field ETest.fld to E1 at sun.reflect.UnsafeFieldAccessorImpl.throwSetIll egalArgumentException(UnsafeFieldAccessorImpl.j ava:146) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIll egalArgumentException(UnsafeFieldAccessorImpl.j ava:150) at sun.reflect.UnsafeObjectFieldAccessorImpl.set(U nsafeObjectFieldAccessorImpl.java:63) at java.lang.reflect.Field.set(Field.java:657) at EnumTroubleToo.main(EnumTroubleToo.java:16)

Tip: Strictly speaking, any attempt to set a field of type X to a value of type Y can only succeed if the following statement holds:
X.class.isAssignableFrom(Y.class) == true

The code could be modified to perform the following test to verify whether the types are compatible:
if (f.getType().isAssignableFrom(E0.cl ass)) // compatible else // expect IllegalArgumentException

95

Anda mungkin juga menyukai