Java Dynamic Programming: Reflection introduction (zz from JR)

Source: Internet
Author: User
Java Dynamic Programming: Reflection Introduction
Use running class information to make your program design more flexible

Reflection grants your code access to the internal information of the Java class loaded into the JVM, and allows you to write the code that works with the selected class during program execution, instead of in the source code. This mechanism makes reflection a powerful tool for creating flexible applications, but be careful that reflection will bring significant side effects if used improperly. In this article, Dennis sosnoski, a software consultant, introduced the use of reflection and the cost of using reflection. Here, you can find out how the Java reflection API allows you to hook objects at runtime.

In the first part, I introduced you to Java programming classes and class loading. The article described a lot of information that appears in the Java binary format. Now I will introduce the basics of Using Reflection APIs to access and use this information at runtime. To make those developers who already know the basics of reflection interested in these things, I will also introduce some performance comparisons between reflection and direct access.

Reflection is different from metadata (data describing other data) in Java programming. Special types of metadata accessed through Java reflection are descriptions of classes and objects within the JVM. Reflection allows you to access various types of information at runtime. It even allows you to read and write attribute fields at runtime and call methods of the selected class.

Reflection is a powerful tool that allows you to build code that can be flexibly assembled at runtime without connecting the source code between components. Some features of reflection also bring about some problems. In this chapter, I will explore the reasons why reflection is not intended in the application, for which reason I think it is used. After you understand the advantages and disadvantages, you will make a decision when the benefits outweigh the disadvantages.

First recognized class
A java. Lang. Class class instance is used when the reflection start point is used. If you work with a predetermined class, the Java language provides a simple shortcut for directly obtaining class instances. For example:
Class CLAS = myclass. Class;
When you use this technology, all work related to the loading class occurs behind the scenes. If you need to read the class name from external resources at runtime, the above method will not achieve your goal. Instead, you need to use the class loader to find the class information, the method is as follows:
// "Name" is the class name to load
Class CLAS = NULL;
Try {
Clas = Class. forname (name );
} Catch (classnotfoundexception ex ){
// Handle exception case
}
// Use the loaded class

If the class has been loaded, you will find information about the current class. If the class has not been loaded, the class loader will load it and return the instance of the recently created class.

Reflection of Classes

The Class Object provides you with all the basic hooks used to reflect metadata of the class. These metadata includes information about the class itself, such as the packages and subclasses of the class, and the interfaces implemented by the class, it also includes the constructors, attribute fields, and detailed information about the methods defined by this class. The following items are frequently used in programming. Therefore, I will give some examples of working with this information at the end of this section.

Java. lang. class provides four independent reflection calls to compile class information in no way. The following lists the standard forms of these four types of calls, which are a group of calls used to find constructors.

Constructor getconstructor (class [] Params) uses the specified parameter type to obtain the public constructor;
Constructor [] getconstructors () obtains all constructors of this class;
Constructor getdeclaredconstructor (class [] Params) uses the specified parameter type to obtain the constructor (ignore the access level)
Constructor [] getdeclaredconstructors () obtain all constructors of this class (ignore the access level)

Each of the above methods returns one or more java. Lang. Reflect. constructor instances. The constructor class defines a newinstance method that requires an object data as a unique parameter, and then returns an instance of the recently created original class. The object array is the parameter value used when the constructor calls. For example, if you have a pair of twostring classes with the string type as the parameter constructor, the Code is as follows:
Public class twostring {
Private string m_s1, m_s2;
Public twostring (string S1, string S2 ){
M_s1 = S1;
M_s2 = S2;
}
}

The following code gets the constructor of the twostring class and uses the strings "A" and "B" to create an instance:
Class [] types = new class [] {string. Class, String. Class };
Constructor cons = twostring. Class. getconstructor (types );
Object [] ARGs = new object [] {"A", "B "};
Twostring Ts = cons. newinstance (ARGs );

The above Code ignores the types of exception checks that may be thrown by different reflection methods. These exceptions are described in detail in the javadoc API, so for simplicity, I will ignore them in all the code.

When it comes to the constructor topic, the Java language also defines a special (or default) constructor shortcut. You can use it to create a class instance. This shortcut is embedded into the class customization like the following code:
Object newinstance ()? Use the default constructor to create a new instance.

Although this method only allows you to use a special constructor, It is a convenient shortcut if you need it. This technique is especially useful when Using JavaBeans because JavaBeans need to define a common constructor without parameters.

Search for Attribute fields through reflection

The class reflection calls the access attribute field information, which is similar to the methods used to access the constructor. Use the attribute field name for parameters of the array type to replace it. The usage is as follows:
Field getfield (string name) -- obtains the public-Level Attribute field specified by name.
Field getfields ()? Obtains all attribute fields of a class with the public level.
Field getdeclaredfield (string name )? Obtains the attribute field declared by class specified by name.
Field getdeclaredfields ()? Obtain all attribute fields defined by the class

Although similar to the constructor call, there is an important difference when it comes to attribute fields: the first two methods return the public (public) that can be accessed through classes) attribute field information (including those from the super class attribute fields). The last two methods return all attribute fields directly declared by the class (the access type of the attribute field is ignored ).

Java. lang. reflect. field instances return all the original data types by calling the defined getxxx and setxxx methods, just like the common get and set methods that work with object references. Although the getxxx method automatically processes data type conversion (for example, getint is used to obtain a byte value ), however, an appropriate method based on the actual attribute field type should be given priority.

The following code shows how to use the attribute field reflection method. By specifying the attribute field name, you can find the int type attribute field of an object and Add 1 to the attribute field value.
Public int incrementfield (string name, object OBJ) throws ...{
Field field = obj. getclass (). getdeclaredfield (name );
Int value = field. getint (OBJ) + 1;
Field. setint (OBJ, value );
Return value;
}

This method begins to show some flexibility that may be brought about by reflection. It works better than a specific class. The incrementfield method passes the object of the class information to the getclass method, then, you can directly search for the named attribute fields in that class.

Search by reflection
The information of the class reflection call access method is very similar to that of the access constructor and field attribute method:
Method getmethod (string name, class [] Params) -- use the specified parameter type to obtain the public type method specified by the name parameter.
Mehtodd [] getmethods ()? Obtain all the public types of a class.
Mehtodd getdeclaredmethod (string name, class [] Params )? Use the specified parameter type to obtain the method specified by the name parameter declared by this class.
Method [] getdeclaredmethods ()? Obtain all the methods declared by this class.

Like calling an attribute field, the first two methods return public methods that can be accessed by instances of this class? Including methods that inherit from superclasses. The last two methods return information about the methods directly declared by this class, regardless of the method access type.

Call the returned java. Lang. Reflect. mehtodd instance to define an invoke method. You can use it to call related instances of the definition class. This invoke method requires two parameters, one is an instance of the class that provides this method, and the other is an array of the parameter values required to call this method.

The following is a more in-depth example than the example of attribute fields. It shows an example of method reflection, this method uses get and set methods to incrementally operate the int type attributes defined by JavaBean. For example, if the object defines the getcount and setcount methods for an integer type count attribute, in order to perform incremental operations for this attribute, you can pass "count" as the parameter name to the called method. The sample code is as follows:
Public int incrementproperty (string name, object OBJ ){
String prop = character. touppercase (name. charat (0) +
Name. substring (1 );
String mname = "get" + Prop;
Class [] types = new class [] {};
Method method = obj. getclass (). getmethod (mname, types );
Object result = method. Invoke (OBJ, new object [0]);
Int value = (integer) result). intvalue () + 1;
Mname = "set" + Prop;
Types = new class [] {Int. Class };
Method = obj. getclass (). getmethod (mname, types );
Method. Invoke (OBJ, new object [] {New INTEGER (value )});
Return value;
}

According to the JavaBeans specification, I converted the first letter of the attribute name into uppercase, and added "get" to the front to create a method name for reading the attribute value, add "set" before the attribute name to create the method name for setting the attribute value. The read method of JavaBeans only returns the attribute value. The write method only needs to write the value as the parameter. Therefore, I have specified the parameter type that matches this method. The final Specification stipulates that these two methods should be of the Public type, so I used the call form to find the public type method of the relevant class.

In this example, I first use reflection to pass a value of the original type, so let's take a look at how it works. The basic principle is simple: whenever you need to pass a value of the original type, you just need to replace the corresponding encapsulated original type (in Java. the instance of the class defined in the lang package. This method can be applied to call and return. Therefore, when I call the get method in my example, the expected result is an actual int type attribute value encapsulated by the java. Lang. Integer class.

Reflection Array

In Java, arrays are objects. Like all other objects, they have classes. If you have an array, you can use the standard getclass method to obtain the class of this array like any other object, but the class you get is different from other object types, the difference is that it does not have an existing working instance. Even if you have an array class, you cannot directly use it to do anything, because the access to the constructor provided by the normal class through reflection cannot work for the array, in addition, the array does not have any accessible attribute fields, and only Java is basically defined for the array object. lang. object type.

Special processing of arrays should use Java. lang. reflect. the array class provides a set of static methods. The methods in this class allow you to create a new array, get the length of an array object, and read and write the index value of an array object.

The following code shows how to effectively adjust the size of an existing array. It uses reflection to create a new array of the same type, and then copies all the data in the original array to the new array before returning the new array.
Public object growarray (Object array, int size ){
Class type = array. getclass (). getcomponenttype (); // obtain the array class
Object grown = array. newinstance (type, size); // obtain the array instance.
System. arraycopy (array, 0, grown, 0,
Math. Min (array. getlength (array), size ));
Return grown;
}

Security and reflection

Security is a complicated problem when dealing with reflection. Reflection is normally used by framework-type code. Because of this, you may often require the framework to fully access your code without having to care about common access restrictions. However, free access may cause some risks in some other instances, for example, when the code is executed in an untrusted code sharing environment.

Because of these conflicts, the Java language defines a multi-level method to handle reflection security. The basic mode is to force the following constraints when requesting source code access:
Access the public components from any place in this class;
Do not access private components outside the class;
Restrict access to the protected and package components.

There is a simple method around these limitations. All constructors, attribute fields, and class methods I used in the previous example are extended to a common base class ??? Java. Lang. Reflect. accessibleobject class. This class defines a setaccessible method, which enables you to enable or disable these access checks for class instances. If the security manager is set to disable access check, access is allowed. Otherwise, the security manager throws an exception.

The following is an instance of the twostring class that uses reverse to demonstrate this behavior.
Public class reflectsecurity {
Public static void main (string [] ARGs ){
Try {
Twostring Ts = new twostring ("A", "B ");
Field field = Clas. getdeclaredfield ("m_s1 ");
// Field. setaccessible (true );
System. Out. println ("retrieved value is" +
Field. Get (insT ));
} Catch (exception ex ){
Ex. printstacktrace (system. Out );
}
}
}

If you compile this code and run the program directly using a command line command without any parameters, it will throw a field. the illegalaccessexception called by get (insT) is abnormal. if you remove the field from the code above. setaccessible (true) line comment, and then compile and re-run the code, it will be successfully executed. Finally, if you add a djava. Security. Manager parameter to the JVM in the command line to make the security manager available, it will fail again unless you define a security license for the reflectsecurity class.

Reflection Performance
Reflection is a powerful tool, but it also has some disadvantages. One of the main disadvantages is the impact on performance. Using Reflection is a basic explanatory operation. You tell JVM what you want to do and what it will do for you. This operation type is always slower than directly performing the same operation. To demonstrate the performance cost of using reflection, I have prepared a benchmark program for this article (which can be downloaded from resources ).

The following is a summary of access performance tests from attribute fields. It includes basic test methods. Each method tests an access attribute field. The accesssame method works with the member field of the object. The accessreference method uses another object attribute field for access, accessreflection is accessed through reflection using the attribute fields of another object. Each method uses the same calculation ??? A simple addition/Multiplication operation in a loop.
Public int accesssame (INT loops ){
M_value = 0;
For (INT Index = 0; index <loops; index ++ ){
M_value = (m_value + additive_value )*
Multiplier_value;
}
Return m_value;
}

Public int accessreference (INT loops ){
Timingclass timing = new timingclass ();
For (INT Index = 0; index <loops; index ++ ){
Timing. m_value = (timing. m_value + additive_value )*
Multiplier_value;
}
Return timing. m_value;
}

Public int accessreflection (INT loops) throws exception {
Timingclass timing = new timingclass ();
Try {
Field field = timingclass. Class.
Getdeclaredfield ("m_value ");
For (INT Index = 0; index <loops; index ++ ){
Int value = (field. getint (timing) +
Additive_value) * multiplier_value;
Field. setint (timing, value );
}
Return timing. m_value;
} Catch (exception ex ){
System. Out. println ("Error Using Reflection ");
Throw ex;
}
}

The test program repeatedly calls each method in a large loop and calculates the average time after the call ends. The first call of each method is not included in the average value, because the initialization time does not affect the result. For the test run done in this article, I use a 10000000 cyclic count for each call and the code runs on the 1 GHz piII system. Three different Linux JVMs are used, and default settings are used for each JVM. The test results are shown in:
 

The scale of the above chart can display the entire test range, but that will reduce the Display Effect of the difference. The first two results charts in this chart are the results of testing with Sun's JVM. The execution time of reflection is more than 1000 times longer than that of direct access. The last figure is a test conducted by the ibm jvm. The execution efficiency of Sun's JVM is higher, but the reflection method is more than 700 times higher than other methods. Although IBM's JVM is almost twice faster than Sun's JVM, there is no significant difference in the execution efficiency of any JVM between two methods other than reflection. Most likely, this difference reflects the small number of dedicated optimizations made by Sun hot spot JVMs in benchmarking simplification.

In addition to testing the access time of attribute fields, I did the same test on the method. For method calls, I tried three methods that are the same as the attribute field access test. I used the variable of the method without parameters to compare with the method call that passed and returned a value. The following code shows three methods for testing using the call method passed and returned values.
Public int calldirectargs (INT loops ){
Int value = 0;
For (INT Index = 0; index <loops; index ++ ){
Value = step (value );
}
Return value;
}

Public int callreferenceargs (INT loops ){
Timingclass timing = new timingclass ();
Int value = 0;
For (INT Index = 0; index <loops; index ++ ){
Value = timing. Step (value );
}
Return value;
}

Public int callreflectargs (INT loops) throws exception {
Timingclass timing = new timingclass ();
Try {
Method method = timingclass. Class. getmethod
("Step", new class [] {Int. Class });
Object [] ARGs = new object [1];
Object value = new INTEGER (0 );
For (INT Index = 0; index <loops; index ++ ){
ARGs [0] = value;
Value = method. Invoke (timing, argS );
}
Return (integer) value). intvalue ();
} Catch (exception ex ){
System. Out. println ("Error Using Reflection ");
Throw ex;
}
}

Display the test results using these methods. Here again, reflection is much slower than other direct access. In the case of no parameter, the execution efficiency is several hundred times slower than sun1.3.1jvm to less than 30 times slower than that of ibm jvm. The difference is not great compared with the case of attribute field access, this is partly because Java. lang. the integer wrapper must pass and return int-type values. Because intergers are unchanged, a new value needs to be generated for the return of each method, which increases the system overhead.

 

The performance of reflection is an area that sun focuses on when developing 1.4jvm. We can see the improvement results. Sun1.4.1jvm has greatly improved this type of operation compared with version 1.3.1. It is about seven times faster in my testing. IBM's 1.4.0jvm provides better performance for such tests, and its running efficiency is two to three times faster than sun1.4.1jvm.

I also wrote a similar efficiency test program for creating objects using reflection. Although this example is not very different from the property field and method call, you can call the newinstance () method on sun1.3.1jvm to create a simple Java. lang. objects are about 12 times longer than new object (). They are about 4 times longer on ibm1.4.0jvm and about 2 times longer on sun1.4.1jvm. For any JVM used for testing, use array. the newinstance (type, size) method takes about two times longer to create an array than new Tye [size]. As the size of the array increases, the difference between the two methods will be reduced accordingly.

Reflection Summary

The reflection mechanism of Java provides a very common method for dynamically connecting program components. It allows your program to create and maintain objects of any class (subject to security restrictions) without the need to hard code the target class in advance. These features make reflection very useful in creating common methods in class libraries that work with objects. For example, reflection is often used in the frameworks of databases, XML, or other external persistent objects.

Reflection has two disadvantages: performance. When using attribute fields and methods for access, reflection is much slower than direct code access. The degree of impact depends on how reflection is used in the program. If it is used as a related program operation that rarely occurs, you do not have to worry about performance reduction, even the most time-consuming reflection operations shown in my tests are only several microseconds. If reflection is used in the core logic of the application, the performance issue becomes a serious object issue.

The disadvantage of many applications is that using reflection can blur the internal logic of your actual code. Programmers all want to see the logic of a program in the source code and some technologies such as maintenance problems that may occur due to reflection bypass the source code. Reflection code is also more complex than the corresponding direct code, as you can see in code instances with better performance. The best way to deal with these problems is to use reflection as little as possible and use it only in some areas that increase flexibility.

In the next article, I will give a more detailed example of how to use reflection. This example provides an API for processing the command line parameters passed to a Java application. While avoiding the weakness, it also shows the powerful functions of reflection. Can reflection use your command to process it easily? You can find the answer in the third part of Java Dynamic Programming.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.