Java reflection class methods

Discovering Class Members

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

Class Methods for Locating Fields

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

Class Methods for Locating Methods

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

Class Methods for Locating Constructors

Class API List of members? Inherited members? Private members?
getDeclaredConstructor() no N/A 1 yes
getConstructor() no N/A 1 no
getDeclaredConstructors() yes N/A 1 yes
getConstructors() yes N/A 1 no

1 Constructors are not inherited.

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

import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Member; import static java.lang.System.out; enum ClassMember < CONSTRUCTOR, FIELD, METHOD, CLASS, ALL >public class ClassSpy < public static void main(String. args) < try < Classc = Class.forName(args[0]); out.format("Class:%n %s%n%n", c.getCanonicalName()); Package p = c.getPackage(); out.format("Package:%n %s%n%n", (p != null ? p.getName() : "-- No Package --")); for (int i = 1; i < args.length; i++) < switch (ClassMember.valueOf(args[i])) < case CONSTRUCTOR: printMembers(c.getConstructors(), "Constructor"); break; case FIELD: printMembers(c.getFields(), "Fields"); break; case METHOD: printMembers(c.getMethods(), "Methods"); break; case CLASS: printClasses(c); break; case ALL: printMembers(c.getConstructors(), "Constuctors"); printMembers(c.getFields(), "Fields"); printMembers(c.getMethods(), "Methods"); printClasses(c); break; default: assert false; >> // production code should handle these exceptions more gracefully > catch (ClassNotFoundException x) < x.printStackTrace(); >> private static void printMembers(Member[] mbrs, String s) < out.format("%s:%n", s); for (Member mbr : mbrs) < if (mbr instanceof Field) out.format(" %s%n", ((Field)mbr).toGenericString()); else if (mbr instanceof Constructor) out.format(" %s%n", ((Constructor)mbr).toGenericString()); else if (mbr instanceof Method) out.format(" %s%n", ((Method)mbr).toGenericString()); >if (mbrs.length == 0) out.format(" -- No %s --%n", s); out.format("%n"); > private static void printClasses(Class c) < out.format("Classes:%n"); Class[] clss = c.getClasses(); for (Class cls : clss) out.format(" %s%n", cls.getCanonicalName()); if (clss.length == 0) out.format(" -- No member interfaces, classes, or enums --%n"); out.format("%n"); > >

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

Читайте также:  Php class session handler

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

$ java ClassSpy java.lang.ClassCastException CONSTRUCTOR Class: java.lang.ClassCastException Package: java.lang Constructor: public java.lang.ClassCastException() public java.lang.ClassCastException(java.lang.String)

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

$ java ClassSpy java.nio.channels.ReadableByteChannel METHOD Class: java.nio.channels.ReadableByteChannel Package: java.nio.channels Methods: public abstract int java.nio.channels.ReadableByteChannel.read (java.nio.ByteBuffer) throws java.io.IOException public abstract void java.nio.channels.Channel.close() throws java.io.IOException public abstract boolean java.nio.channels.Channel.isOpen()

The interface java.nio.channels.ReadableByteChannel defines read() . The remaining methods are inherited from a super interface. This code could easily be modified to list only those methods that are actually declared in the class by replacing get*s() with getDeclared*s() .

$ java ClassSpy ClassMember FIELD METHOD Class: ClassMember Package: -- No Package -- Fields: public static final ClassMember ClassMember.CONSTRUCTOR public static final ClassMember ClassMember.FIELD public static final ClassMember ClassMember.METHOD public static final ClassMember ClassMember.CLASS public static final ClassMember ClassMember.ALL Methods: public static ClassMember ClassMember.valueOf(java.lang.String) public static ClassMember[] ClassMember.values() public final int java.lang.Enum.hashCode() public final int java.lang.Enum.compareTo(E) public int java.lang.Enum.compareTo(java.lang.Object) public final java.lang.String java.lang.Enum.name() public final boolean java.lang.Enum.equals(java.lang.Object) public java.lang.String java.lang.Enum.toString() public static T java.lang.Enum.valueOf (java.lang.Class,java.lang.String) public final java.lang.Class java.lang.Enum.getDeclaringClass() public final int java.lang.Enum.ordinal() public final native java.lang.Class java.lang.Object.getClass() public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException public final void java.lang.Object.wait() hrows java.lang.InterruptedException public final native void java.lang.Object.notify() public final native void java.lang.Object.notifyAll()

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.

Источник

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 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  < 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   %n"); return; > try < Classc = 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); 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(); >> >

Deet 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 :

Locale.class == pType[0].getClass()
$ 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 3-letter 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 distinction in the handling of checked versus unchecked exceptions. They are all wrapped in an InvocationTargetException

Читайте также:  Шаблон css для регистрация

Invoking Methods with a Variable Number of Arguments

Method.invoke() 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.

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 < Classc = 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 invoking Deet.main() invoking testDeet() Locale = Japanese (Japan,JP), ISO Language Code = jpn testDeet() returned true

Источник

Оцените статью