What is the difference between Class.forName and ClassLoader?

Foreword

Recently, I was asked during the interview, the difference between loading classes with Class.forName () and loading classes with ClassLoader in Java reflection. I didn't think of it at the time, but after I studied it myself, I wrote it down and recorded it.

Explanation

Class.forName () and ClassLoader can load classes in java. ClassLoader is a class loader that follows the parent delegation model and finally calls the startup class loader. The function it implements is "to obtain a binary byte stream describing this class through the fully qualified name of a class." After obtaining the binary stream, it is placed in the JVM . Class.forName () method is actually implemented by calling CLassLoader.

Class.forName (String className); the source code of this method is

@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    Class<?> caller = Reflection.getCallerClass();
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

The last method called is the method forName0. The second parameter in the forName0 method is set to true by default. This parameter represents whether to initialize the loaded class. When set to true, the class will be initialized, which means that the class will be executed. The static code block, and the assignment of static variables and other operations.

You can also call Class.forName (String name, boolean initialize, ClassLoader loader) method to manually choose whether to initialize the class when loading the class. The source code of Class.forName (String name, boolean initialize, ClassLoader loader) is as follows:

/* @param name       fully qualified name of the desired class
 * @param initialize if {@code true} the class will be initialized.
 *                   See Section 12.4 of <em>The Java Language Specification</em>.
 * @param loader     class loader from which the class must be loaded
 * @return           class object representing the desired class
 *
 * @exception LinkageError if the linkage fails
 * @exception ExceptionInInitializerError if the initialization provoked
 *            by this method fails
 * @exception ClassNotFoundException if the class cannot be located by
 *            the specified class loader
 *
 * @see       java.lang.Class#forName(String)
 * @see       java.lang.ClassLoader
 * @since     1.2     */
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
                               ClassLoader loader)
    throws ClassNotFoundException
{
    Class<?> caller = null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        // Reflective call to get caller class is only needed if a security manager
        // is present.  Avoid the overhead of making this call otherwise.
        caller = Reflection.getCallerClass();
        if (sun.misc.VM.isSystemDomainLoader(loader)) {
            ClassLoader ccl = ClassLoader.getClassLoader(caller);
            if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                sm.checkPermission(
                    SecurityConstants.GET\_CLASSLOADER\_PERMISSION);
            }
        }
    }
    return forName0(name, initialize, loader, caller);
}

The comments in the source code only take a part, and the description of the parameter initialize is: if {@code true} the class will be initialized. Meaning: If the parameter is true, the loaded class will be initialized.

Examples

Here is an example to illustrate the results:

A class containing static code blocks, static variables, and static methods assigned to static variables

public class ClassForName {

    //静态代码块
    static {
        System.out.println("执行了静态代码块");
    }
    //静态变量
    private static String staticFiled = staticMethod();

    //赋值静态变量的静态方法
    public static String staticMethod(){
        System.out.println("执行了静态方法");
        return "给静态字段赋值了";
    }

}

Use the test method of Class.forName ():

@Test
public void test45(){
    try {
        ClassLoader.getSystemClassLoader().loadClass("com.eurekaclient2.client2.ClassForName");
        System.out.println("#########-------------结束符------------##########");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

operation result:

执行了静态代码块执行了静态方法#########-------------结束符------------##########  

Test method using ClassLoader:

@Test
public void test45(){
    try {
        ClassLoader.getSystemClassLoader().loadClass("com.eurekaclient2.client2.ClassForName");
        System.out.println("#########-------------结束符------------##########");
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
}

operation result:

#########-------------结束符------------##########

According to the operation result, it is concluded that Class.forName initializes the class when loading the class, and ClassClass of loadClass does not initialize the class, but just loads the class into the virtual machine.

Application scenario

The implementation of IOC in the familiar Spring framework is the ClassLoader used.

When we use JDBC, we usually use the Class.forName () method to load the database connection driver. This is because the JDBC specification clearly requires that the Driver (database driver) class must register itself with the DriverManager.

Take the MySQL driver as an example to explain:

public class Driver extends NonRegisteringDriver implements java.sql.Driver {  
    // ~ Static fields/initializers  
    // ---------------------------------------------  
  
    //  
    // Register ourselves with the DriverManager  
    //  
    static {  
        try {  
            java.sql.DriverManager.registerDriver(new Driver());  
        } catch (SQLException E) {  
            throw new RuntimeException("Can't register driver!");  
        }  
    }  
  
    // ~ Constructors  
    // -----------------------------------------------------------  
  
    /** 
     * Construct a new driver and register it with DriverManager 
     *  
     * @throws SQLException 
     *             if a database error occurs. 
     */  
    public Driver() throws SQLException {  
        // Required for Class.forName().newInstance()      }  

}

We see that the driver registration in DriverManager is written in the static code block, which is why Class.forName () is used when writing JDBC.

Ok, I wrote about this today. I have encountered a lot of problems in the interview recently, and I have learned a lot. Although it is very tired, it has also made people grow a lot. Various kinds of questions, various scenarios for various interviewers in various enterprises. Come on, find a company that will allow you to work for at least a few years. Do n’t always let me run into a company that breaks down after a while. Otherwise, I am very helpless.

After finding a job, I will summarize my experience.

Author: Ji Mo https://www.cnblogs.com/jimoer/p/9185662.html

Pay attention to the WeChat public account of the Java technology stack. The stack leader will continue to share fun Java technology. The public account will be pushed as soon as possible and reply in the background of the public account: Java, you can get historical Java tutorials, all are dry goods.

I recommend going to my blog to read more:

1. Java JVM, collection, multithreading, new features series tutorials

2. Spring MVC, Spring Boot, Spring Cloud series of tutorials

3. Maven, Git, Eclipse, Intellij IDEA series of tool tutorials

4. The latest interview questions for Java, backend, architecture, Alibaba and other major manufacturers

Life is beautiful, see you tomorrow ~

495 original articles have been published · 1032 thumbs up · 1.46 million views

Guess you like

Origin blog.csdn.net/youanyyou/article/details/105528782