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 }
运行结果如下:
不要让任何事情成为你不去学习的理由!
转载原处: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去请求。