Java reflection mechanism (IV)-in-depth instantiation Methods
Reflection mechanism these blog posts are written down and found to involve the Java class loading mechanism. This part of content is also a relatively independent part, so it is written separately. In JAVA, any class must be loaded into JVM to run. Previously, Class Loader introduced the loading mechanism of classes. Here we will talk about the comparison between different loading methods, so that we can have a deeper understanding of the JAVA Class instantiation process.
New and Class. newInstance we say that the new keyword in the code means that the coupling of code that may change is too high. In this case, we will use the reflection mechanism to remove the new Keyword, which we have seen in the proxy mode. In fact, Class. newInstance is used instead. This indicates that both methods can get the same object instance, but there is a difference between them, and the coupling degree is different.
In fact, we can think that the Class. newInstanc method to instantiate an object is to split the new Keyword into two steps. Because the usage of Class. newInstance is prerequisite, ensure that the Class has been loaded to JVM and linked. See the following code:
Public static void main (String [] arg) throws ClassNotFoundException, InstantiationException, IllegalAccessException {// get the currently running loader ClassLoader cl = Thread from the current Thread. currentThread (). getContextClassLoader (); cl. loadClass ("com. zjj. classTest. test "); // load the Test Class to JVM Class c2 = cl. getClass (); // obtain the Class Object c2.newInstance () of the Class; // instantiate the object }}
Here, Class. forName is not used to obtain the Class object to ensure that the Class is loaded but not linked. This code looks like there is nothing wrong with it, and there is no problem with compilation, but an error occurs during running. That is to say, the class loaded using the above method is not linked, so the newInstance method cannot be executed.
Previously, we can simply think that the Class. Instance method is the two steps of the new split, but in fact the new method does more than the Class. Instance method. The Class. Instance method can only access constructor without parameters, but can access all new constructor methods. Create a test class with two constructors and check the client call code:
public static void main(String[] arg) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ Class c=Class.forName("com.zjj.ClassTest.Test"); c.newInstance(); new Test("ni"); }}
Output result:
Constructors without Parameters
Constructors with Parameters
If you input a parameter in newInstance to call a constructor with a parameter, an error is returned and compilation fails. NewInstance is weak and new is strong.
Class. forName and classLoad. loadClass: before talking about these two differences, we should first understand that JVM will execute static code segments. Remember the concept that static code is bound to class, if the class is loaded successfully, the static code is executed and the static code will not be followed. That is to say, the static code segment is executed only once when the class is loaded. In addition, we also need to know that the loading process of classes is divided into loading, connection, and initialization. In addition, when the JVM encounters a Class request, it first checks whether the memory exists. If the memory does not exist, it loads it. If the memory does not exist, it returns an existing Class object.
The difference between the two methods is that the three processes are different. ForName has two functions (polymorphism). If forName (String className, boolean initialize, ClassLoader loader) is set to True, the class is linked and initialized. If it is set to False, it will not be connected or initialized if it does not exist. If there is a connected Class object, it will be returned but will not be initialized. The default value of initialize is True for a single parameter.
When loadClass is also a single parameter of multi-state loadClass (String name), resolve = false. If the Class has been loaded by the class loader, return the instance of the loaded Class. Otherwise, use the custom class loader to load the Class, at this time, I do not know whether the connection is successful. It will never be initialized! The only guarantee is that this class is loaded. But I don't know if this class is connected and initialized.
When loadClass (String name, boolean resolve) resolve = true, it is guaranteed that it has been loaded and connected. When resolve = falses, it is only to load this class and does not care whether it is connected or not, so it may be connected or not. The following code verifies the above content through testing:
Test class:
Public class Test {static {System. out. println ("static initialization");} public Test () {System. out. println ("constructor without Parameters");} public Test (String str) {System. out. println ("constructor with Parameters");} {System. out. println ("non-static initialization ");}}
Test 1: Client call code
public static void main(String[] arg) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ Class c=Class.forName("com.zjj.ClassTest.Test"); }}
The output result is static initialization.
Note: Class. forName performs three steps: Loading, connection, and initialization.
Test 2: Changed the client code
public static void main(String[] arg) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ ClassLoader cl=Thread.currentThread().getContextClassLoader(); Class c=Class.forName("com.zjj.ClassTest.Test", false, cl); }}
If the output result is initialize = true, It is output and initialized statically. No output when the value is false.
Note: If this parameter is set to true, the class performs three steps: Loading, connection, and initialization. If this parameter is set to false, no Initialization is performed.
Test 3: Changed the client code
public static void main(String[] arg) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ ClassLoader cl=Thread.currentThread().getContextClassLoader(); Class c=Class.forName("com.zjj.ClassTest.Test", false, cl); c.newInstance(); }}
Output result:
Static Initialization
Non-static Initialization
Constructors without Parameters
Note: To ensure that no previously loaded class exists in the JVM, the JVM memory is specially cleared. But the output result remains unchanged. If it is false, the load and link are executed. Otherwise, newInstance cannot be executed (the execution condition of newInstance was mentioned earlier ). However, the information says there may still be no connection !! To be verified.
Test 4: Changed the client code
public static void main(String[] arg) throws ClassNotFoundException, InstantiationException, IllegalAccessException{ Class c=Class.forName("com.zjj.ClassTest.Test"); ClassLoader cl=Thread.currentThread().getContextClassLoader(); Class c=Class.forName("com.zjj.ClassTest.Test", true, cl); }}
The output result is static initialization.
Note: If a previously loaded class exists, the returned class exists when the second load request is executed. Because static Initialization is only executed once.
Test 5: Changed the client code
Public static void main (String [] arg) throws ClassNotFoundException, InstantiationException, IllegalAccessException {// get the currently running loader ClassLoader cl = Thread from the current Thread. currentThread (). getContextClassLoader (); cl. loadClass ("com. zjj. classTest. test "); // load the Test Class to JVM Class c2 = cl. loadClass ("com. zjj. classTest. test "). getClass (); // obtain the Class Object c2.newInstance () of the Class; // instantiate the object }}
Output result: an error is returned.
Note: Classes loaded into the memory by the loadClass method are not connected at this time and will not be initialized. Therefore, there is no static initialization output.
Test 6: I don't know why the ClassLoader in the Code has two loadClass methods.
Summary:At this point, the method comparison is over. This blog focuses on a more detailed understanding of the JVM loading process and the differences between different methods. In fact, it is only the difference in the degree of encapsulation, that is, the difference in the granularity of methods. Of course, one thing has not been verified through my own tests. It may be that my method is incorrect or there is a problem with the information. And write down this question! Goodbye to the next blog!