The reflection library gives you a very rich and elaborate toolset to write programsthat manipulate Java code dynamically. This feature is heavily used in JavaBeans, the component architecture for Java (see Volume II for more on JavaBeans). Using reflection, Java can support tools like the ones to which users of Visual Basic have grown accustomed. In particular, when new classes are added at design or runtime, rapid application development tools can dynamically inquire about the capabilities of the classes that were added.
A program that can analyze the capabilities of classes is called reflective. The reflection mechanism is extremely powerful. As the next sections show, you can use it to
Reflection is a powerful and complex mechanism; however, it is of interest mainly to tool builders, not application programmers. If you are interested in programming applications rather than tools for other Java programmers, you can safely skip the remainder of this section and return to it later.
The Class Class
While your program is running, the Java runtime system always maintains what iscalled runtime type identification on all objects. This information keeps track of the class to which each object belongs. Runtime type information is used by the virtual machine to select the correct methods to execute.
However, you can also access this information by working with a special Java class. The class that holds this information is called, somewhat confusingly, Class. The getClass()
method in the Object class returns an instance of Class type.
Just like an Employee object describes the properties of a particular employee, a Class object describes the properties of a particular class. Probably the most commonly used method of Class is getName. This returns the name of the class. For example, the statementprints Employee Harry Hacker if e is an employee, or Manager Harry Hacker if e is a manager.
If the class is in a package, the package name is part of the class name:
You can obtain a Class object corresponding to a class name by using the static forName method.
You would use this method if the class name is stored in a string that varies at runtimeruntime.
This works if className is the name of a class or interface. Otherwise, the forName method throws a checked exception.
TIP: At startup, the class containing your main method is loaded. It loads all classes that it needs. Each of those loaded classes loads the classes that it needs, and so on. That can take a long time for a big application, frustrating the user. You can give users of your program the illusion of a faster start with the following trick. Make sure that the class containingthe main method does not explicitly refer to other classes. First display a splash screen. Thenmanually force the loading of other classes by calling Class.forName.
A third method for obtaining an object of type Class is a convenient shorthand. If T is any Java type, then T.class is the matching class object. For example:
Note that a Class object really describes a type, which may or may not be a class. For example, int is not a class, but int.class is nevertheless an object of type Class.
NOTE: As of Java SE 5.0, the Class class is parameterized. For example, Employee .class is of type Class<Employee>. We are not dwelling on this issue because it would further complicate an already abstract concept. For most practical purposes, you can ignore the type parameter and work with the raw Class type.
CAUTION: For historical reasons, the getName method returns somewhat strange names for array types:
Another example of a useful method is one that lets you create an instance of a class onthe fly. This method is called, naturally enough, newInstance(). For example,
creates a new instance of the same class type as e. The newInstance method calls the default constructor (the one that takes no parameters) to initialize the newly created object. An exception is thrown if the class has no default constructor.
Using a combination of forName and new Instance lets you create an object from a class name stored in a string.
NOTE:If you need to provide parameters for the constructor of a class you want to create by name in this manner, then you can’t use statements like the preceding. Instead, you must use the newInstance method in the Constructor class.
C++ NOTE: The newInstance method corresponds to the idiom of a virtual constructor in C++. However, virtual constructors in C++ are not a language feature but just an idiom that needs to be supported by a specialized library. The Class class is similar to the type_info class in C++, and the get Class method is equivalent to the typeid operator. The Java Class is quite a bit more versatile than type _info, though. The C++ type_info can only reveal a string with the name of the type, not create new objects of that type.
A Primer on Catching Exceptions
We cover exception handling fully later, but in the meantime you will occasionally encounter methods that threaten to throw exceptions. When an error occurs at runtime, a program can “throw an exception.” Throwing an exception is more flexible than terminating the program because you can provide a handlerthat “catches” the exception and deals with it.
If you don’t provide a handler, the program still terminates and prints a message to the console, giving the type of the exception. You may already have seen exception reports when you accidentally used a null reference or overstepped the bounds of an array.
There are two kinds of exceptions: unchecked exceptions and checked exceptions. With checked exceptions, the compiler checks that you provide a handler. However, many common exceptions, such as accessing a null reference, are unchecked. The compiler does not check whether you provide a handler for these errors —after all, you should spend your mental energy on avoiding these mistakes rather than coding handlers for them.
But not all errors are avoidable. If an exception can occur despite your best efforts, then the compiler insists that you provide a handler. The Class.forName method is an example of a method that throws a checked exception.
Place one or more statements that might throw checked exceptions inside a try block. Then provide the handler code in the catch clause.
If the class name doesn’t exist, the remainder of the code in the try block is skipped and the program enters the catch clause. (Here, we print a stack trace by using the printStack-
Trace method of the Throwable class. Throwable is the superclass of the Exception class.) If none of the methods in the try block throws an exception, the handler code in the catch clause is skipped.
You only need to supply an exception handler for checked exceptions. It is easy to find out which methods throw checked exceptions—the compiler will complain whenever you call a method that threatens to throw a checked exception and you don’t supply a handler.
section on reflection for more information on how to supply parameters.
The three classes Field, Method, and Constructor in the java.lang.reflect package describe the fields, methods, and constructors of a class, respectively. All three classes have a method called getName that returns the name of the item. The Field class has a method getType that returns an object, again of type Class, that describes the field type. The Method and Constructor classes have methods to report the types of the parameters, and the Method class also reports the return type. All three of these classes also have a method called getModifiers that returns an integer, with various bits turned on and off, that describes the modifiers used, such as public and static. You can then use the static methods in the Modifier class in the java .lang .reflect package to analyze the integer that
getModifiers returns. Use methods like isPublic, isPrivate, or isFinal in the Modifier class to tell whether a method or constructor was public, private, or final. All you have to do ishave the appropriate method in the Modifier class work on the integer that get Modifiers returns. You can also use the Modifier.toString method to print the modifiers.
The getFields, getMethods, and get Constructors methods of the Class class return arrays of the public fields, methods, and constructors that the class supports. This includes public members of superclasses. The get DeclaredFields, getDeclaredMethods, and get Declared Constructors methods of the Class class return arrays consisting of all fields, methods, and constructors that are declared in the class. This includes private and protected members, but not members of superclasses.
Listing below shows you how to print out all information about a class. The program prompts you for the name of a class and then writes out the signatures of all methods and constructors as well as the names of all data fields of a class. For example, if you enter
What is remarkable about this program is that it can analyze any class that the Java interpreter can load, notjust the classes that were available when the program was compiled.
We use this program in the next chapter to peek inside the inner classes that the Java compiler generates automatically.
getFields returns an array containing Field objects for the public fields of this class or its superclasses; getDeclaredField returns an array of Field objects for all fields of this class. The methods return an array of length 0 if there are no such fields or if the Class object represents a primitive or array type.
returns the Class object for the class that defines this constructor, method, or field.
tests the bit in the modifiers value that corresponds to the modifier in the method name.
Using Reflection to Analyze Objects at Runtime
In the preceding section, we saw how we can find out the names and types of the datafields of any object:
Of course, it is easy to look at the contents of a specific field of an object whose nameand type are known when you write a program. But reflection lets you look at fields ofobjects that were not known at compile time.
The key method to achieve this examination is the get method in the Field class. If f isan object of type Field (for example, one obtained from getDeclaredFields) and obj is anobject of the class of which f is a field, then f.get(obj) returns an object whose valueis the current value of the field of obj. This is all a bit abstract, so let’s run through anexample.
Actually, there is a problem with this code. Because the name field is a private field,the get method will throw an IllegalAccessException. You can only use the get method toget the values of accessible fields. The security mechanism of Java lets you find outwhat fields any object has, but it won’t let you read the values of those fields unlessyou have access permission.
The default behavior of the reflection mechanism is to respect Java access control. However,if a Java program is not controlled by a security manager that disallows it, you canoverride access control. To do this, invoke the setAccessible method on a Field, Method, or Constructor object. For example:
The setAccessible method is a method of the Accessible Object class, the common superclass ofthe Field, Method, and Constructor classes. This feature is provided for debuggers, persistent storage, and similar mechanisms. We use it for a generic toString method later in this section.
There is another issue with the get method that we need to deal with. The name field is aString, and so it is not a problem to return the value as an Object. But suppose we want tolook at the salary field. That is a double, and in Java, number types are not objects. To handlethis, you can either use the getDouble method of the Field class, or you can call get,whereby the reflection mechanism automatically wraps the field value into the appropriate wrapper class, in this case, Double.
Of course, you can also set the values that you can get. The call f.set(obj, value) sets thefield represented by f of the object obj to the new value.
Listing below shows how to write a generic toString method that works for any class. Ituses get Declared Fields to obtain all data fields. It then uses the set Accessible convenience method to make all fields accessible. For each field, it obtains the name and the value.
Listing below turns each value into a string by recursively invoking toString .class ObjectAnalyzer
The complete code in Listing below needs to address a couple of complexities. Cycles ofreferences could cause an infinite recursion. Therefore, the ObjectAnalyzer keeps track ofobjects that were already visited. Also, to peek inside arrays, you need a differentapproach. You’ll learn about the details in the next section.
You can use this toString method to peek inside any object. For example, the callyields the printout
You can use this generic toString method to implement the toString methods of your ownclasses, like this:
is a convenience method to set the accessibility flag for an array of objects.
gets the field that is declared in this class with the given name, or an array of all fields.
Using Reflection to Write Generic Array Code
The Array class in the java .lang .reflect package allows you to create arrays dynamically.For example, when you use this feature with the arraycopy method , youcan dynamically expand an existing array while preserving the current contents.The problem we want to solve is pretty typical. Suppose you have an array of some typethat is full and you want to grow it. And suppose you are sick of writing the grow-andcopycode by hand. You want to write a generic method to grow an array.
How can we write such a generic method? It helps that an Employee array can be convertedto an Object array. That sounds promising. Here is a first attempt to write ageneric method. We simply grow the array by 10% + 10 elements (because the 10 percentgrowth is not substantial enough for small arrays).
However, there is a problem with actually using the resulting array. The type of arraythat this code returns is an array of objects (Object) because we created the array usingthe line of code
An array of objects cannot be cast to an array of employees (Employee). Java would generatea ClassCastException at runtime. The point is, as we mentioned earlier, that a Javaarray remembers the type of its entries, that is, the element type used in the new expressionthat created it. It is legal to cast an Employee temporarily to an Object array andthen cast it back, but an array that started its life as an Object array can never be castinto an Employee array. To write this kind of generic array code, we need to be able tomake a new array of the same type as the original array. For this, we need the methods ofthe Array class in the java .lang .reflect package. The key is the static newInstance method ofthe Array class that constructs a new array. You must supply the type for the entries andthe desired length as parameters to this method.
To actually carry this out, we need to get the length and component type of the new array.
We obtain the length by calling Array .getLength(a). The static getLength method of the Arrayclass returns the length of any array. To get the component type of the new array:
Why is getLength a method of Array but get Component Type a method of Class? We don’t know—the distribution of the reflection methods seems a bit ad hoc at times.Here’s the code:
Note that this arrayGrow method can be used to grow arrays of any type, not just arraysof objects.
To make this possible, the parameter of goodArrayGrow is declared to be of type Object, not anarray of objects ( Object). The integer array type int can be converted to an Object, butnot to an array of objects!
Listing below shows both array grow methods in action. Note that the cast of the return value of badArrayGrow will throw an exception.
NOTE: We present this program to illustrate how to work with arrays through reflection. If you just want to grow an array, use the copyOf method in the Arrays class.
(xxx is one of the primitive types boolean, byte, char, double, float, int, long, short.) These methods return the value of the given array that is stored at the given index.
(xxx is one of the primitive types boolean, byte, char, double, float, int, long, short.) These methods store a new value into the given array at the given index.
returns a new array of the given component type with the given dimensions.
On the surface, Java does not have method pointers—ways of giving the location of a method to another method so that the second method can invoke it later. In fact, the designers of Java have said that method pointers are dangerous and error prone andthat Java interfaces (discussed in the next chapter) are a superior solution. However, as of
Java it turns out that Java does have method pointers, as a (perhaps accidental) byproduct of the reflection package.
NOTE: Among the nonstandard language extensions that Microsoft added to its Java derivative J++ (and its successor, C#) is another method pointer type, called a delegate, that is different from the Method class that we discuss in this section. However, inner classes (which we will introduce in the next chapter) are a more useful construct than delegates.
To see method pointers at work, recall that you can inspect a field of an object with the get method of the Field class. Similarly, the Method class has an invoke method that lets you call the method that is wrapped in the current Method object. The signature for the invoke method is
The first parameter is the implicit parameter, and the remaining objects provide the explicit parameters. (Before Java SE 5.0, you had to pass an array of objects or null if the method had no explicit parameters.)
For a static method, the first parameter is ignored —you can set it to null. For example, if m1 represents the getName method of the Employee class, the following code
As with the get and set methods of the Field type, there’s a problem if the parameter orreturn type is not a class but a primitive type. You either rely on auto boxing or, before Java SE 5.0, wrap primitive types into their corresponding wrappers.
Conversely, if the return type is a primitive type, the invoke method will return the wrapper type instead. For example, suppose that m2 represents the getSalary method of the Employee class. Then,the returned object is actually a Double, and you must cast it accordingly.
As of Java SE 5.0, automatic unboxing takes care of the rest.
How do you obtain a Method object? You can, of course, call getDeclaredMethods and search through the returned array of Method objects until you find the method that you want. Or, you can call the getMethod method of the Class class. This is similar to the getField method that takes a string with the field name and returns a Field object. However, there may be several methods with the same name, so you need to be careful that you get the right one. For that reason, you must also supply the parameter types of the desired method.
The signature of getMethod is
For example, here is how you can get method pointers to the getName and raiseSalary methods of the Employee class:
(Before Java SE 5.0, you had to package the Class objects into an array or to supply null if there were no parameters.)
Now that you have seen the rules for using Method objects, let’s put them to work. Listing below is a program that rints a table of values for a mathematical function such asMath.sqrt or Math.sin. The printout looks like this: public static native double java.lang.Math.sqrt(double) 1.0000 | 1.0000 2.0000 | 1.4142 3.0000 | 1.7321 4.0000 | 2.0000 5.0000 | 2.2361 6.0000 | 2.4495 7.0000 | 2.6458 8.0000 | 2.8284 9.0000 | 3.0000 10.0000 | 3.1623
Thecode for printing a table is, of course, independent of the actual function that isbeing tabulated.
Here, f is an object of type Method. The first parameter of invoke is null because we are calling a static method. To tabulate the Math.sqrt function, we set f to
That is the method of the Math class that has the name sqrt and a single parameter of type double.
As this example shows clearly, you can do anything with Method objects that you can do with function pointers in C (or delegates in C#). Just as in C, this style of programming is usually quite inconvenient and always error prone. What happens if you invoke a method with the wrong parameters? The invoke method throws an exception.
Also, the parameters and return values of invoke are necessarily of type Object. That means you must cast back and forth a lot. As a result, the compiler is deprived of the chance to check your code. Therefore, errors surface only during testing, when they are more tedious to find and fix. Moreover, code that uses reflection to get at method pointers is significantly slower than code that simply calls methods directly.
For that reason, we suggest that you use Method objects in your own programs only when absolutely necessary. Using interfaces and inner classes (the subject of the next chapter) is almost always a better idea. In particular, we echo the developers of Java and suggest not using Method objects for callback functions. Using interfaces for the callbacks leads to code that runs faster and is a lot more maintainable.
Core Java Related Interview Questions
|J2EE Interview Questions||Core Java Interview Questions|
|JDBC Interview Questions||JSP Interview Questions|
|Android Interview Questions||JavaServer Faces (JSF) Interview Questions|
|Java collections framework Interview Questions||Java 8 Interview Questions|
|Java Collections Interview Questions||Java Exception Handling Interview Questions|
|Java Concurrency Interview Questions||Java Serialization Interview Questions|
|Java Programmer Interview Questions||Java Inheritance Interview Questions|
|Java IO Interview Questions||Object Oriented Programming in PHP Interview Questions|
Core Java Tutorial
An Introduction To Java
The Java Programming Environment
Fundamental Programming Structures In Java
Objects And Classes
Interfaces And Inner Classes
User Interface Components With Swing
Deploying Applications And Applets
Exceptions, Logging, Assertions, And Debugging
All rights reserved © 2020 Wisdom IT Services India Pvt. Ltd
Wisdomjobs.com is one of the best job search sites in India.