Java基础面试题6-Java反射中Class.forName和classloader的区别

Java中Class.forName和classloader都可以用来对类进行加载。

 

Class.forName除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。

而classloader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。

 

Class.forName(name,initialize,loader)带参数也可控制是否加载static块。并且只有调用了newInstance()方法采用调用构造函数,创建类的对象。

 

代码如下:

复制代码
 1 package com.mangosoft.java.reflect;
 2 
 3 /**
 4  * Created by zhangshengjian on 2017/3/1.
 5  */
 6 public class Line {
 7     static {
 8         System.out.println("static code executing: loading line...");
 9     }
10 }
复制代码
复制代码
 1 package com.mangosoft.java.reflect;
 2 
 3 /**
 4  * Created by zhangshengjian on 2017/3/1.
 5  */
 6 public class Point {
 7     static {
 8         System.out.println("static code executing: loading point...");
 9     }
10 }
复制代码
复制代码
 1 package com.mangosoft.java.reflect;
 2 
 3 /**
 4  * classloader和Class.forName的区别
 5  *
 6  * Created by zhangshengjian on 2017/3/1.
 7  */
 8 public class ClassLoaderAndForNameTest {
 9 
10     public static void main(String[] args) {
11         String wholeNameLine = "com.mangosoft.java.reflect.Line";
12         String wholeNamePoint = "com.mangosoft.java.reflect.Point";
13 
14         System.out.println("classloader testing...");
15         testClassLoader(wholeNameLine, wholeNamePoint);
16         System.out.println("---------------------------------------");
17         System.out.println("Class.forName testing...");
18         testForName(wholeNameLine, wholeNamePoint);
19     }
20 
21     //classloader
22     public static void testClassLoader(String wholeNameLine, String wholeNamePoint) {
23         ClassLoader loader = ClassLoader.getSystemClassLoader();
24         Class line;
25         Class point;
26         try {
27             line = loader.loadClass(wholeNameLine);
28             point = loader.loadClass(wholeNamePoint);
29             System.out.println("line " + line.getName());
30             System.out.println("point " + point.getName());
31         } catch (ClassNotFoundException e){
32             e.printStackTrace();
33         }
35     }
36 
37     //Class.forName
38     public static void testForName(String wholeNameLine, String wholeNamePoint) {
39         try {
40             Class line = Class.forName(wholeNameLine);
41             Class point = Class.forName(wholeNamePoint);
42             System.out.println("line " + line.getName());
43             System.out.println("point " + point.getName());
44         } catch (ClassNotFoundException e) {
45             e.printStackTrace();
46         }
47     }
48 }
复制代码

 

运行结果如下:

Java基础面试题6-Java反射中Class.forName和classloader的区别_第1张图片

 

不要让任何事情成为你不去学习的理由!


转载原处:https://www.cnblogs.com/mangosoft/p/6485790.html


在理解这两种反射机制之前,需要弄清楚java类的加载机制.

装载:通过类的全限定名获取二进制字节流(二进制的class文件),将二进制字节流转换成方法区中的运行时数据结构,在内存中生成Java.lang.class对象。这个时候该类型没有被分配内存,设置默认值,也没有初始化。

链接:执行下面的校验、准备和解析步骤,其中解析步骤是可以选择的;

  校验:检查导入类或接口的二进制数据的正确性;(文件格式验证,元数据验证,字节码验证,符号引用验证)

  准备:给类的静态变量分配并初始化存储空间;

  解析:将常量池中的符号引用转成直接引用;

初始化:激活类的静态变量的初始化Java代码和静态Java代码块,并初始化程序员设置的变量值。

Class.forName有两个重载方法:

复制代码
 public static Class forName(String name, boolean initialize,
                   ClassLoader loader)
        throws ClassNotFoundException


 public static Class forName(String className) 
                throws ClassNotFoundException
复制代码

解释:

name:类的全限定名,如:com.org.prj
initialize:如果为true,则会在返回Class对象之前,对该类型做连接,校验,初始化操作。(如:执行static块中的代码),initialize默认需要初始化。
loader:用自定义的类加载器来请求这个类型;当然,你也可以传入null,用bootstrap加载器

由于Class.forName默认是需要初始化,一旦初始化,就会触发目标对象的 static块代码执行,static参数也也会被再次初始化。

我们在来看ClassLoader.loadClass也有两个两个重载方法:

protected synchronized Class loadClass(String name, boolean resolve)
    throws ClassNotFoundException

public Class loadClass(String name) throws ClassNotFoundException 

解释:

name:类的全限定名,如:com.org.prj

resolve:表示是否需要连接该类型。 仅仅是连接(这里面包括校验class文件,准备分配内存,类型常量池的替换),并不会初始化该类型。

resolve默认是不链接,不进行链接意味着不进行包括初始化等一些列步骤,那么静态块和静态对象就不会得到执行。

总结:

1.Class.forName返回的Class对象可以决定是否初始化。而ClassLoader.loadClass返回的类型绝对不会初始化,最多只会做连接操作。 
2.Class.forName可以决定由哪个classLoader来请求这个类型。而ClassLoader.loadClass是用当前的classLoader去请求。


你可能感兴趣的:(java面试)