Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the use of the reflection mechanism in Java

2025-01-16 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article will explain in detail what is the use of the reflection mechanism in Java. The editor thinks it is very practical, so I share it for you as a reference. I hope you can get something after reading this article.

First, what is reflection?

(1) the core of Java reflection mechanism is to dynamically load the class and obtain the details of the class when the program is running, so as to manipulate the properties and methods of the class or object. The essence is that after JVM gets the class object, it decompiles through the class object to obtain all kinds of information about the object.

(2) Java belongs to the language that compiles and then runs, the type of objects in the program is determined at compile time, and when the program is running, some classes may need to be loaded dynamically, these classes are not loaded into JVM because they are not needed before. With reflection, you can dynamically create an object and call its properties at run time without knowing in advance who the running object is at compile time.

Second, why use reflection

First, we have an interface X and its method test, and two corresponding implementation classes An and B:

Public class Test {interface X {public void test ();} class An implements X {@ Override public void test () {System.out.println ("I am A");}} class B implements X {@ Override public void test () {System.out.println ("I am B");}}

Usually, we can just new which implementation class we need to use. Take a look at the following code:

Public class Test {. Public static void main (String [] args) {X a = create1 ("A"); a.test (); X b = create1 ("B"); b.test ();} public static X create1 (String name) {if (name.equals ("A")) {return new A () } else if (name.equals ("B")) {return new B ();} return null;}}

According to the above, if there are hundreds of different X implementation classes that need to be created, don't we need to write thousands of if statements to return different X objects?

Let's look at how the reflection mechanism works:

Public class Test {public static void main (String [] args) {X a = create2 ("A"); a.test (); X b = create2 ("B"); b.testReflect ();} / / using reflection mechanism public static X create2 (String name) {Class class = Class.forName (name); X x = (X) class.newInstance (); return x;}}

Pass the package name and class name to the create2 () method, dynamically load the specified class through the reflection mechanism, and then instantiate the object.

After reading the above example, I believe you have a certain understanding of reflection. Reflection has the following four functions:

Learn the class to which any object belongs at run time (dynamic compilation).

Construct an object of any class at run time.

Learn the member variables and methods that any class has at run time.

Call the methods and properties of any object at run time.

The above function of dynamically obtaining information and dynamically calling the methods of objects is called the reflection mechanism of the Java language.

Class III. Class

To understand reflection, you must first understand the Class class, because the Class class is the foundation of the reflection implementation.

While the program is running, JVM always maintains a type ID called runtime for all objects, which tracks the complete structural information of the class to which each object belongs, including package name, class name, implemented interface, owned methods and fields, and so on. You can access this information through a special Java class, which is the Class class. We can think of the Class class as the type of the class, a Class object called the type object of the class, and a Class object corresponds to a .class file loaded into the JVM.

In general, there must be a class before an object. Take the following code as an example, the normal loading process of a class is as follows:

Import java.util.Date; / / public class Test {public static void main (String [] args) {Date date = new Date (); / / object System.out.println (date);}}

First, JVM compiles your code into a .class bytecode file, which is then loaded into JVM memory by the class loader (Class Loader), and creates a Class object of the Date class to be stored in the heap (note that this is not an object from new, but a type object of the class). Before creating a Date object, JVM checks whether its class is loaded, looks for the corresponding Class object of the class, and if so, allocates memory for it, and then initializes new Date ().

It is important to note that there is only one Class object per class, which means that if we have a second new Date () statement, JVM will not generate another Class object for Date, because one already exists. This also allows us to use the = = operator to compare two class objects:

System.out.println (date.getClass () = = Date.getClass ()); / / true

Then after loading a class, the method area of the heap memory produces a Class object, which contains the complete structure information of the class. We can see the structure of the class through this Class object, just like a mirror. So we call it vividly: reflection.

Speak in more detail and explain again. As mentioned above, under normal circumstances, there must be a class and then an object, which we call "positive". Then the "inverse" in reflection can be understood as finding the class to which the object belongs (the origin of the object).

Date date = new Date (); System.out.println (date.getClass ()); / / "class java.util.Date"

Through reflection, that is, after calling the getClass () method, we get the Class object corresponding to the Date class, see the structure of the Date class, and output the full name of the class to which the Date object belongs, that is, we find the source of the object. Of course, there's more than one way to get a Class object.

Four ways to get Class class objects

From the source code of the Class class, we can see that its constructor is private, that is, only JVM can create an object of the Class class, and we can't directly new a Class object like a normal class.

We can only get a Class class object from an existing class, and Java provides four ways:

The first: if you know the specific class, you can use:

Class alunbarClass = TargetObject.class

However, we generally do not know the specific class. Basically, we get the Class object by traversing the class under the package. Getting the Class object in this way will not be initialized.

Second, pass in the full class name through Class.forName () to obtain:

Class alunbarClass1 = Class.forName ("com.xxx.TargetObject")

What is actually called inside this method is forName0:

The second boolean parameter indicates whether the class needs to be initialized, which is required by default. Once initialized, the static block code execution of the target object is triggered, and the static parameter is initialized again.

The third is obtained from the object instance instance.getClass ():

Date date = new Date (); Class alunbarClass2 = date.getClass (); / / get the Class class object of the object instance

Fourth: pass in the classpath through the class loader xxxClassLoader.loadClass ().

Class clazz = ClassLoader.LoadClass ("com.xxx.TargetObject")

Getting Class objects through the class loader is not initialized, which means that static blocks and static objects are not executed without a series of steps, including initialization. Here is a comparison with forName.

five。 Construct an instance of a class by reflection

Above we described how to get an object of the Class class, so after successfully getting it, we need to construct an instance of the corresponding class. Here are three methods, the first one is the most common, and the last one can be understood a little.

① uses Class.newInstance

For example:

Date date1 = new Date (); Class alunbarClass2 = date1.getClass (); Date date2 = alunbarClass2.newInstance (); / / create an instance with the same class type as alunbarClass2

An instance with the same class type as alunbarClass2 is created.

Note that the newInstance method calls the default constructor (no-parameter constructor) to initialize the newly created object. If the class does not have a default constructor, an exception is thrown.

② first gets the constructor through reflection and then calls

Since not all classes have a nonparametric constructor or the class constructor is private, Class.newInstance is not satisfied if we still want to instantiate objects through reflection.

At this point, we can use the newInstance method of Constructor to get the constructor and then execute the constructor.

It's easy to see from the above code that Constructor.newInstance can take parameters, while Class.newInstance is parameterless, which is why it can only call no-argument constructors.

Let's not confuse these two newInstance methods. If the constructor of the called class is the default constructor, using Class.newInstance () is a better choice. If you need to call the class's parameterized constructor, private constructor, etc., you need to use Constractor.newInstance () in a sentence of OK;.

Constructor.newInstance is the method that executes the constructor. Let's take a look at the channels through which the constructor can be obtained, such as its name. The following methods are easy to remember and easy to understand, and the return values are received through the Cnostructor type.

Batch get constructor:

1) get all "public" constructors

Public Constructor [] getConstructors () {}

2) get all constructors (including private, protected, default, public)

Public Constructor [] getDeclaredConstructors () {} single get constructor:

1) get a "public" constructor of the specified parameter type

Public Constructor getConstructor (Class... ParameterTypes) {}

2) get a "constructor" of the specified parameter type, which can be private, protected, default, or public

Public Constructor getDeclaredConstructor (Class... ParameterTypes) {}

For example:

Package fanshe;public class Student {/ / (default constructor) Student (String str) {System.out.println ("(default) constructor s =" + str);} / / parameterless constructor public Student () {System.out.println ("Public, parameterless constructors are executed.") ;} / / the constructor with one parameter public Student (char name) {System.out.println ("name:" + name); / / the constructor with multiple parameters public Student (String name, int age) {System.out.println ("name:" + name+ "age:" + age); / / there is a problem with the execution efficiency, which will be solved later. } / / protected constructor protected Student (boolean n) {System.out.println ("protected constructor n =" + n);} / / private constructor private Student (int age) {System.out.println ("private constructor age:" + age) }}-- public class Constructors {public static void main (String [] args) throws Exception {/ / load Class object Class clazz = Class.forName ("fanshe.Student"); / / get all public constructors Constructor [] conArray = clazz.getConstructors () For (Constructor c: conArray) {System.out.println (c);} / / get all constructors (including: private, protected, default, public) conArray = clazz.getDeclaredConstructors (); for (Constructor c: conArray) {System.out.println (c) } / / get the public, no-parameter constructor / / because it is a no-parameter constructor, so the type is a null. It is OK not to write: what is needed here is a parameter type, and remember that the type / / returns the class object that describes the no-parameter constructor. Constructor con = clazz.getConstructor (null); Object obj = con.newInstance (); / / call constructor / / get private constructor con = clazz.getDeclaredConstructor (int.class); System.out.println (con); con.setAccessible (true); / / in order to call private method / domain we need to cancel the security check obj = con.newInstance (12) / / call constructor}} ③ uses open source library Objenesis

Objenesis is an open source library. Like the second method above, you can call any constructor, but the encapsulation is relatively simple:

Public class Test {/ / No parameter constructor private int i; public Test (int I) {this.i = I;} public void show () {System.out.println ("test..." + I);}}-public static void main (String [] args) {Objenesis objenesis = new ObjenesisStd (true) Test test = objenesis.newInstance (Test.class); test.show ();}

It is very easy to use, and Objenesis is implemented by the subclass ObjenesisObjenesisStd. Detailed source code here do not delve into, understand it.

six。 Get member variables through reflection and use the

Similar to getting the constructor, getting member variables is also divided into batch acquisition and individual acquisition. The return value is received through the Field type.

Batch acquisition:

1) get all public fields

Public Field [] getFields () {}

2) get all fields (including private, protected, default)

Public Field [] getDeclaredFields () {} single acquisition:

1) get a public field of the specified name

Public Field getField (String name) {}

2) get a field with a specified name, which can be private, protected, or default

Public Field getDeclaredField (String name) {}

After you get the member variables, how do you modify their values?

The set method contains two parameters:

Obj: which object modifies this member variable

Value: which value to change to

For example:

Package fanshe.field;public class Student {public Student () {} public String name; protected int age; char sex; private String phoneNum; @ Override public String toString () {return "Student [name=" + name + ", age=" + age + ", sex=" + sex + ", phoneNum=" + phoneNum + "]" }}-- public class Fields {public static void main (String [] args) throws Exception {/ / get the Class object Class stuClass = Class.forName ("fanshe.field.Student"); / / get the public no-parameter constructor Constructor con = stuClass.getConstructor () / / get private constructor con = clazz.getDeclaredConstructor (int.class); System.out.println (con); con.setAccessible (true); / / in order to call the private method / domain, we need to cancel the security check obj = con.newInstance (12); / / call the constructor / / get all public fields Field [] fieldArray = stuClass.getFields () For (Field f: fieldArray) {System.out.println (f);} / / get all fields (including private, protected, default) fieldArray = stuClass.getDeclaredFields (); for (Field f: fieldArray) {System.out.println (f) } / / get the public field Field f = stuClass.getField ("name") of the specified name; Object obj = con.newInstance (); / / call the constructor to create an instance of the class f.set (obj, "Andy Lau"); / / assign a value to the name attribute in the Student object / / get the private field f = stuClass.getDeclaredField ("phoneNum") F.setAccessible (true); / / violence reflex, release the private qualification f.set (obj, "18888889999"); / / assign a value to the phoneNum attribute in the Student object. Get the member method through reflection and call the

Similarly, the method of getting members is also divided into batch acquisition and individual acquisition. The return value is received through the Method type.

Batch acquisition:

1) get all "public methods" (including the methods of the parent class and, of course, the Object class)

Public Method [] getMethods () {}

2) get all member methods, including private (excluding inherited)

Public Method [] getDeclaredMethods () {} single acquisition:

Gets a member method that specifies the method name and parameter type:

Public Method getMethod (String name, Class... ParameterTypes)

How do I call methods after I get them?

The invoke method contains two parameters:

Obj: which object will call this method

Args: the argument passed when the method is called

For example:

Package fanshe.method;public class Student {public void show1 (String s) {System.out.println ("called: public, String parameter show1 (): s =" + s);} protected void show2 () {System.out.println ("called: protected, no parameter show2 ()");} void show3 () {System.out.println ("called: default, no parameter show3 ()") } private String show4 (int age) {System.out.println ("called, private, and returned, show4 (): age =" + age) of the int parameter; return "abcd" }}-public class MethodClass {public static void main (String [] args) throws Exception {/ / get Class object Class stuClass = Class.forName ("fanshe.method.Student"); / / get the public no-parameter constructor Constructor con = stuClass.getConstructor () / / get all public methods stuClass.getMethods (); Method [] methodArray = stuClass.getMethods (); for (Method m: methodArray) {System.out.println (m);} / / get all methods, including private methodArray = stuClass.getDeclaredMethods (); for (Method m: methodArray) {System.out.println (m) } / / get the public show1 () method Method m = stuClass.getMethod ("show1", String.class); System.out.println (m); Object obj = con.newInstance (); / / call the constructor to instantiate a Student object m.invoke (obj, "veal") / / get private show4 () method m = stuClass.getDeclaredMethod ("show4", int.class); m.setAccessible (true); / / unqualify private Object result = m.invoke (obj, 20); System.out.println ("return value:" + result);}} eight. Advantages and disadvantages of reflection mechanism

Advantages: it is flexible and can dynamically obtain instances of the class at run time.

Disadvantages:

1) performance bottleneck: reflection is the equivalent of a series of interpretive operations that tell JVM what to do, and performance is much slower than direct Java code.

2) Security issues: the reflection mechanism destroys encapsulation because private methods and fields of the class can be obtained and called through reflection.

nine。 Classic application scenarios of reflection

Reflection is not directly and extensively used in our actual programming, but there are actually many designs related to reflection mechanisms, such as:

The dynamic proxy mechanism uses JDBC to connect to the database Spring / Hibernate framework (in fact, it is related to the reflection mechanism because the dynamic proxy is used)

Why dynamic agents use reflection mechanisms will be explained in detail in the next article.

JDBC connects to the database

In the operation of JDBC, if you want to connect to the database, you must follow these steps:

Load the driver of the database through Class.forName () (load through reflection)

Connect to the database through the DriverManager class, and the parameters include the connection address, user name and password of the database.

Receive a connection through the Connection interface

Close the connection

Public static void main (String [] args) throws Exception {Connection con = null; / / database connection object / / 1\. Load the driver Class.forName ("com.mysql.jdbc.Driver") through reflection; / / 2\. Connect to the database con = DriverManager.getConnection ("jdbc:mysql://localhost:3306/test", "root", "root"); / / 3\. Close the database connection con.close ();} Spring framework

Reflection mechanism is the soul of Java framework design, the interior of the framework has been sealed, we basically do not need to write. Typically, in addition to Hibernate, Spring also uses a lot of reflection mechanisms. The most typical is that Spring loads Bean (create object) through the xml configuration file, that is, the IoC of Spring. The process is as follows:

Load configuration file and get Spring container

Use the reflection mechanism to get a Class instance of a class based on the passed string

/ / get the IoC container of Spring, and get the object public static void main (String [] args) {/ / 1 according to id. Use the ApplicationContext API to load the configuration file and get the spring container ApplicationContext ac = new ClassPathXmlApplicationContext ("spring.xml"); / / 2\. Using the reflection mechanism, get the Class instance of a class IAccountService aService = (IAccountService) ac.getBean ("accountServiceImpl"); System.out.println (aService) from this string } this is the end of the article on "what is the use of reflection in Java?". I hope the above content can be of some help to you, so that you can learn more knowledge. if you think the article is good, please share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report