What is the difference between Class.forName and lassLoader?

Keywords: Java Spring JDBC Database

Preface

Recently, during an interview, I was asked the difference between a Class.forName() loading class and a ClassLoader loading class in the Java reflection.I didn't come up with it at that time. I studied it myself and wrote it down.

explain

Class.forName() and lassLoader can both load classes in java.ClassLoader is a class loader that follows the parental delegation model and ultimately calls the startup class loader. It implements the function of "getting a binary byte stream describing this class by its fully qualified name", getting it into the binary stream and putting it into the JVM.The Class.forName() method is actually implemented by calling LassLoader.

Class.forName(String className); the source code for 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 invoked is forName0, in which the second parameter is set to true by default, which represents whether the loaded class is initialized or not, and when set to true, the class is initialized, which represents the execution of static code blocks in the class, assignments to static variables, and so on.

You can also call the Class.forName(String name, boolean initialize,ClassLoader loader) method to manually choose whether to initialize the class when it is loaded.The source code for 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 are excerpted, and the parameter initialize is described as if {@code true} the class will be initialized. This means that if the parameter is true, the loaded class will be initialized.

Give an example

Here are some examples to illustrate the results:

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

public class ClassForName {

	//Static Code Block
	static {
	    System.out.println("Executed static code block");
	}
	//Static variable
	private static String staticFiled = staticMethod();

	//Static methods for assigning static variables
	public static String staticMethod(){
	    System.out.println("Executed static method");
	    return "Assigned static fields";
	}
	
}

Using the Class.forName() test method:

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

Run result:

Executed static code block Executed static method ##########---------------------------------------------- #############  

Test methods using ClassLoader:

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

Run result:

###########\#------------------------------------------------------------------############

Class.forName loads classes into initialization based on the results of the run, while ClassLoader's loadClass does not initialize classes but loads classes into virtual machines.

Application Scenarios

The implementation of IOC in the Spring framework that we are familiar with is using ClassLoader.

When we use JDBC, we usually use the Class.forName() method to load the database connection driver.This is because the JDBC specification explicitly requires Driver (database-driven) classes to register themselves with DriverManager.

Take the drive for MySQL as an example:

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 actions registered with Driver Manager are written in static code blocks, which is why Class.forName() is used when writing JDBC.

Okay, I've written this today. Recently in the interview, I encountered a lot of problems and learned a lot. Although tired, I also grew up a lot. After all, the interview is a peeling process, and I will encounter various problems and scenes from various enterprises and interviewers.Go ahead and find a company that will keep you working for at least a few years. Don't always let me run into a situation where the company collapses before long.Otherwise, I would be very helpless.

When you find a job, you'll summarize what you've experienced.

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

Keep an eye on the Java technology stack WeChat Public Number. The stack leader will continue to share interesting Java technology. The Public Number will be pushed for the first time and will reply in the Public Number background: Java, you can get historical Java tutorials, they are all dry goods.

Recommend going to my blog to read more:

1.Java JVM, Collections, Multithreaded, New Features Series Tutorial

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

3.Maven, Git, Eclipse, Intellij IDEA Series Tools Tutorial

4.Latest Interview Questions for Java, Backend, Architecture, Alibaba, etc.

Life is good. See you tomorrow~

Posted by like_duh44 on Tue, 14 Apr 2020 19:49:52 -0700