1. What is reflection
1. First knowledge reflex
When I first started to learn reflection, I was confused. This thing is really "abstract mother opens the door to abstract - abstract is home."
Why do you need to get the Class object before creating an object? Isn't that unnecessary? Isn't it easier for me to new directly?
What is the program runtime to get the properties and methods of a class? Usually, the code is modified after the program compilation error. Why should I consider the running state of the program?
I don't usually use it for development. What's the use of learning this thing?
Later, after learning annotation, spring, spring MVC and other technologies, I found that reflection is everywhere.
2.JVM loading class
The java program we write should be run in the JVM, so to learn reflection, we first need to understand the process of loading classes in the JVM.
1. We wrote it java files are called source code.
2. We write a main method in a class, and then click the run button of IDEA. When the JVM runs, it will trigger the javac instruction of jdk to compile the source code into Class file, which is also called bytecode file.
3. The JVM class loader (you can understand it as a tool) obtains the binary byte stream of a class through the fully qualified name of the class, and then loads the class file into the method area of the JVM.
4. Load a Class loader When the Class file is to the method area, a unique Class object will be generated in the heap. This Class contains the member variables, construction methods and member methods of this Class.
5. This Class object will create an object instance corresponding to this Class.
So on the surface, you create a new object. In fact, when the JVM runs the program, it is the Class object of this Class that really helps you create the object.
In other words, reflection is actually that the JVM encapsulates all classes you create into a unique Class object when running the program. This Class object contains properties, constructor methods, and member methods. When you get the Class object, you can get these three things.
After you get the attribute of the reflection Class, you can get the attribute name, attribute Class and attribute value of the object, and set the value for the attribute.
After you get the Class constructor, you can create the object.
After you get the member method of the reflection (Class), you can execute the method.
3. The concept of reflection
java reflection mechanism is to know all the properties and methods of any class in the running state of the program; For any object, you can call any of its methods and properties; This function of dynamically obtaining information and dynamically calling object methods is called the reflection mechanism of java language.
Knowing the process of loading classes by JVM, I believe you should have a deeper understanding of the concept of reflection.
Reflection: JVM runtime -- > Java file -- > Class file -- > class object -- > creates an object instance and operates the properties and methods of the instance
Next, I'll talk about related classes and common methods in reflection.
2. Class object
Get Class object
Create a User class first:
public class User { private String name = "Know you"; public String sex = "male"; public User() { } public User(String name, String sex) { this.name = name; this.sex = sex; } public void eat(){ System.out.println("People want to eat!"); } private void run(){ System.out.println("People want to run!"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } }
There are three ways to get Class objects:
1. Class.forName("full class name")
Full class name: package name + class name
Class userClass = Class.forName("com.xxl.model.User");
2. Class name class
Class userClass = User.class;
3. Object getClass()
User user = new User(); Class userClass = user.getClass();
Although there are three ways to obtain Class objects, we generally use the first method above.
After we get the Class object, we can operate the methods related to it.
3. Get class name
1. Get the complete class name: package name + class name
getName()
Class userClass = Class.forName("com.xxl.model.User"); String name = userClass.getName(); System.out.println(name);
Print results:
2. Get simple class name: excluding package name
getSimpleName()
Class userClass = Class.forName("com.xxl.model.User"); String simpleName = userClass.getSimpleName(); System.out.println(simpleName);
Print results:
4. Properties
4.1 get attributes
1. Get all public attributes: public modifier
getFields()
Class userClass = Class.forName("com.xxl.model.User"); Field[] fields = userClass.getFields(); for (Field field : fields) { System.out.println(field); }
Print results:
2. Get a single public attribute
getField("property name")
Class userClass = Class.forName("com.xxl.model.User"); Field field = userClass.getField("sex"); System.out.println(field);
Print results:
3. Get all attributes: public + Private
getDeclaredFields()
Class userClass = Class.forName("com.xxl.model.User"); Field[] fields = userClass.getDeclaredFields(); for (Field field : fields) { System.out.println(field); }
Print results:
4. Get a single attribute: public or private
Getdeclaraedfield ("property name")
Class userClass = Class.forName("com.xxl.model.User"); Field nameField = userClass.getDeclaredField("name"); Field sexField = userClass.getDeclaredField("sex"); System.out.println(nameField); System.out.println(sexField);
Print results:
4.2 operation attributes
1. Get attribute name
getName()
Class userClass = Class.forName("com.xxl.model.User"); Field nameField = userClass.getDeclaredField("name"); System.out.println(nameField.getName());
Print results:
2. Get attribute type
getType()
Class userClass = Class.forName("com.xxl.model.User"); Field nameField = userClass.getDeclaredField("name"); System.out.println(nameField.getType());
Print results:
3. Get attribute value
get(object)
Class userClass = Class.forName("com.xxl.model.User"); Field nameField = userClass.getDeclaredField("sex"); User user = new User(); System.out.println(nameField.get(user));
Print results:
Note: the value of the private attribute cannot be obtained directly through reflection, but the value of the private attribute can be obtained by modifying the access entry.
Set allowed access to private properties:
field.setAccessible(true);
For example:
Class userClass = Class.forName("com.xxl.model.User"); Field nameField = userClass.getDeclaredField("name"); nameField.setAccessible(true); User user = new User(); System.out.println(nameField.get(user));
Printing method:
4. Set attribute value
set(object, "attribute value")
Class userClass = Class.forName("com.xxl.model.User"); Field nameField = userClass.getDeclaredField("name"); nameField.setAccessible(true); User user = new User(); nameField.set(user,"zhang wuji"); System.out.println(nameField.get(user));
Print results:
5. Construction method
1. Get all public construction methods
getConstructors()
Class userClass = Class.forName("com.xxl.model.User"); Constructor[] constructors = userClass.getConstructors(); for (Constructor constructor : constructors) { System.out.println(constructor); }
Print results:
2. Obtain the construction method matching the parameter type
Getconstructor (parameter type)
Class userClass = Class.forName("com.xxl.model.User"); Constructor constructor = userClass.getConstructor(String.class, String.class); System.out.println(constructor);
Print results:
6. Membership method
6.1 method of obtaining members
1. Access to all public methods
getMethods()
Class userClass = Class.forName("com.xxl.model.User"); Method[] methods = userClass.getMethods(); for (Method method : methods) { System.out.println(method); }
Print results:
We found that in addition to the custom public methods, there are also public methods inherited from the Object class.
2. Get a public method
getMethod("method name", parameter type)
Class userClass = Class.forName("com.xxl.model.User"); Method method = userClass.getMethod("setName", String.class); System.out.println(method);
Print results:
3. Get all methods: public + Private
getDeclaredMethods()
Class userClass = Class.forName("com.xxl.model.User"); Method[] declaredMethods = userClass.getDeclaredMethods(); for (Method method : declaredMethods) { System.out.println(method); }
Print results:
4. Get a method: public or private
Getdeclaraedmethod ("method name", parameter type)
Class userClass = Class.forName("com.xxl.model.User"); Method method = userClass.getDeclaredMethod("run"); System.out.println(method);
Print results:
6.2 executive member method
invoke(object, "method parameter")
Class userClass = Class.forName("com.xxl.model.User"); Method method = userClass.getDeclaredMethod("eat"); User user = new User(); method.invoke(user);
Print results:
Note: private member methods cannot be executed directly through reflection, but access can be set.
Set the allowed private methods:
method.setAccessible(true);
7. Notes
1. Judge whether a class or method contains an annotation
isAnnotationPresent(Annotation name.class)
For example:
Class userClass = Class.forName("com.xxl.model.User"); if(userClass.isAnnotationPresent(Component.class)){ Component annotation = (Component)userClass.getAnnotation(Component.class); String value = annotation.value(); System.out.println(value); };
2. Get comments
getAnnotation(Annotation name.class)
For example:
Class userClass = Class.forName("com.xxl.model.User"); // Get annotation on class Annotation annotation1 = userClass.getAnnotation(Component.class); Method method = userClass.getMethod("eat"); // Gets an annotation on a method Annotation annotation2 = userClass.getAnnotation(Component.class);
8. Create an instance of the class
1. Instantiate objects through Class
Class.newInstance()
Class userClass = Class.forName("com.xxl.model.User"); User user = (User)userClass.newInstance(); System.out.println("full name:"+user.getName()+" Gender:"+user.getSex());
Print results:
2. Instantiate objects through construction methods
constructor. Newinstance (parameter value)
Class userClass = Class.forName("com.xxl.model.User"); Constructor constructor = userClass.getConstructor(String.class, String.class); User user = (User)constructor.newInstance\("Li Shiqing", "female"\); System.out.println("full name:"+user.getName()+" Gender:"+user.getSex());
Print results:
9. Reflection cases
One day, the technical director said to Zhang San, "Zhang San, I heard that you have learned reflection recently. Then you design an object factory class and show it to me."
Zhang San thought, "Oh, it's almost the new year. The leader is going to give me a raise. I'll do well this time."
Five minutes later, Zhang San submitted the code:
public class ObjectFactory { public static User getUser() { User user = null; try { Class userClass = Class.forName("com.xxl.model.User"); user = (User) userClass.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } return user; } public static UserService getUserService() { UserService userService = null; try { Class userClass = Class.forName("com.xxl.service.impl.UserServiceImpl"); userService = (UserService) userClass.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } return userService; } }
The technical director glanced at the code and said to Zhang San, "there are two problems in your factory class."
1. There is a lot of redundancy in the code. If there are 10000 classes, do you want to write 10000 static methods?
2. Code coupling is too high. If the package path of these classes changes, will it be a problem if you use forName() to get the Class object? You have to manually change the code one by one, and then compile, package and deploy it.. Don't you find it troublesome?
"Spread your thinking and think about whether you can only design a static class and create objects with reflection by passing parameters. The passed parameters should reduce the coupling with the factory class. By the way, you can refer to the way JDBC obtains database connection parameters."
Zhang Sanyi Listened: "it's worthy of being the director. Be enlightened! Wait for me for 10 minutes."
After 10 minutes, Zhang San submitted the code again:
object.properties
user=com.xxl.model.User userService=com.xxl.service.impl.UserServiceImpl
ObjectFactory
public class ObjectFactory { private static Properties objectProperty = new Properties(); // Static methods are executed at class initialization and only once static{ try { InputStream inputStream = ObjectFactory.class.getResourceAsStream("/object.properties"); objectProperty.load(inputStream); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } public static Object getObject(String key){ Object object = null; try { Class objectClass = Class.forName(objectProperty.getProperty(key)); object = objectClass.newInstance(); } catch (Exception e) { e.printStackTrace(); } return object; } }
Test method:
@Test void testObject() { User user = (User)ObjectFactory.getObject("user"); UserService userService = (UserService)ObjectFactory.getObject("userService"); System.out.println(user); System.out.println(userService); }
Execution results:
After seeing this, the director nodded again and again, smiled and said to Zhang San: "using the properties file to store the fully qualified name of the class reduces the coupling degree of the code, and using reflection to create objects by passing parameters reduces the redundancy of the code. This time, it can be changed“
"Well, the project will go online tonight. Let's have dinner first and fix the bug later."
Zhang San: "...... good director."
10. Function of reflection
We have more or less heard that reflection is used when designing frameworks. For example, Spring IOC uses factory pattern and reflection to create objects, and the bottom layer of BeanUtils also uses reflection to copy attributes. So reflection is everywhere.
Although we hardly use reflection in our daily development, we must understand the principle of reflection, because it can help us understand the principle of framework design.