Let’s take a look at these concepts before we look at Java reflection.
1. Interpreted and compiled languages
Interpreted languages: translate explanations line by line at run time without compiling. Code can be modified directly and can be deployed quickly, but with slightly worse performance than compiled languages; JavaScript, Python;
Compiled languages: the source code needs to be compiled into machine code by a compiler to execute; If the code needs to be modified after compilation, it needs to be recompiled before execution. Such as C language;
Java is also strictly a compiled language, but somewhere between compiled and interpreted; Java does not generate machine code directly, but intermediate code: during compilation, the source code is handed to the compiler to generate class files (bytecodes), which are translated rather than run in memory. When run time comes, bytecode is loaded by the Java virtual machine, interpreted into machine language, and run.
2. Dynamic and static languages
Dynamic language: it means that the program can change its structure at run time, and determine the data type at run time. Whether an object can perform a certain operation depends only on whether it has the corresponding method, rather than whether it is a certain type of object. Like JavaScript, Python.
Static languages: In contrast to dynamic languages, the data type of the variable is determined at compile time (the data type must be declared before using the variable), and the type match is performed at compile time; Such as C language, Java;
3. The concept of reflection
Java reflection: At runtime, all properties and methods of any class can be known; You can call properties and methods of any object; This ability to dynamically retrieve class information and invoke object methods is called Java reflection.
Since reflection has a “negative” in it, let’s first look at what “positive” is.
In Java, to use a method in a class, “forward” looks like this:
ArrayList list = new ArrayList(); / / instantiate
list.add("reflection"); // Execute method
Copy the code
So how does the reverse work?
Class clz = Class.forName("java.util.ArrayList");
Method method_add = clz.getMethod("add".Object.class);
Constructor constructor = clz.getConstructor();
Object object = constructor.newInstance();
method_add.invoke(object."reflection");
Method method_get = clz.getMethod("get",int.class);
System.out.println(method_get.invoke(object.0));
Copy the code
The two pieces of code execute the same result, but the “forward” code already knows what class to run (ArrayList) before compiling, whereas the second piece of code only knows when the code is running that the class is java.util.arrayList.
4. The role of reflection
At this point, some of you might be wondering, “What’s the use of reflection? I already know that the class I’m going to use is ArrayList. Can’t I just new an object and execute its methods?”
Of course you can! But in many cases, you don’t know which class to use until the code runs, or you decide which class to use at run time;
For example, there is such a function: “call Ali Cloud face recognition API”; This is not easy, refer to the other side of the API documentation, can be quickly implemented.
faceRecognition(Object faceImg){
// Call aliyun face recognition API
}
Copy the code
A month after the launch, the leader said: “our company began to cooperate with Tencent cloud, face recognition interface to change.”
faceRecognition(Object faceImg){
// Call Tencent cloud face recognition API
}
Copy the code
The modification went online for two months, and the leader said, “Change it back.” …
Of course, a smart programmer would think of setting up a switch configuration to let the switch decide which code logic to follow. If the leader wants to become a service of Amazon Cloud someday, just write if-else:
faceRecognition(Object faceImg){
if("AL".equals(configStr)){
// Call aliyun face recognition API
}else if("TX".equals(configStr)){
// Call Tencent cloud face recognition API
}else if("AM".equals(configStr)){
// Call amazon cloud face recognition API
}
}
Copy the code
But there’s a better way:
1. Define an interface:
interface FaceRecognitionInterface(a){
faceRecognition(Object faceImg) ;
}
Copy the code
2. Multiple implementation classes:
class ALFaceRecognition implements FaceRecognitionInterface{
// Call ali cloud face recognition API implementation
}
class TXFaceRecognition implements FaceRecognitionInterface{
// Call Tencent cloud face recognition API implementation
}
Copy the code
3 in the call face recognition function of the code:
String configStr = "Read configuration, go Ali Cloud or Tencent cloud";
FaceRecognitionInterface faceRe = Class.forName(configStr).newInstance();
faceRe.faceRecognition(faceImg);
Copy the code
If you look at the example above, you still feel that doing if-else in A calling method is not too different from using reflection implementation, but what if programmer A provides the interface, programmer B provides the implementation, and programmer C writes the client?
Recall the use of JDBC, such as creating a connection:
public Connection getConnection(a) throws Exception{
Connection conn = null;
// Initialize the driver class
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection("jdbc:mysql://url"."root"."admin");
return conn;
}
Copy the code
Among them:
- Programmer A provides the interface: Oracle corporation (formerly Sun) provides the JDBC standard (interface); When you define the interface, you don’t know how many database implementations there will be;
- Programmer B provides the implementation: Each database vendor provides the implementation for its own database.
- Programmer C write client: I code farmers in Java code access to the database.
To summarize the role of Java reflection: It is possible to design more general and flexible architectures, and many frameworks can load different classes based on configuration to ensure their universality. In addition:
- Dynamic proxy: Enhancing a method without changing the target object method, such as using AOP to intercept some method printing logs, requires reflection to execute the contents of the method.
- Annotations: Use reflection to retrieve annotations and perform corresponding actions.
5. Use reflection
We know that the Java runtime source file is a class file (bytecode), so to use reflection, we need to get bytecode file objects. In Java, there are three ways to get bytecode file objects:
- Call the class property of a class: class name.class
- Call the object’s getClass() method: object.getClass ()
- Use the forName() static method in the Class Class: class.forname (the full path of the Class), which is recommended
The java.lang.Reflect class library provides support for reflection:
- Field: Properties of an object can be read and modified using the get and set methods.
- Method: You can use the invoke() Method to call a Method on an object;
- Constructor: Create new objects using newInstance().
6. Pros and cons of reflection
Advantages: Dynamically obtain the contents of classes and objects at runtime, which greatly improves the flexibility and expansibility of the system; To exaggerate, reflection is the soul of frame design.
Disadvantages: There is a performance penalty and the JVM cannot optimize this code; Break the encapsulation of classes.
All in all, you may not feel like you’ve written reflection code in your normal development, but reflection is everywhere in the open source frameworks we use.
Uncle will point code | article “original”