每天学一点(类加载器1)好多java技术书中的笔误
今台看了一点关于类加载器的东西,总结一下算作一个小复习吧,尽可能的每天学习一点知识点,积水成渊吧
?
首先我们如何看当一个类运行的时候相关的加载信息呢 在命令行下可以采用java -verbose:class 类名称 ,如果是在eclipse下(本人其实用的是myeclipse) 设置一下运行参数就可以。如下图
?
这样你就可以在运行的时候就可以看到相关类是如何加载的
我们运行一下
?
你会看到类似如下的信息,只是类似并不是雷同。
?
[Opened D:\Program Files\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre\lib\rt.jar]
[Loaded java.lang.Object from D:\Program Files\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre\lib\rt.jar]
[Loaded java.io.Serializable from D:\Program Files\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre\lib\rt.jar]
[Loaded java.lang.Comparable from D:\Program Files\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre\lib\rt.jar]
[Loaded java.lang.CharSequence from D:\Program Files\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre\lib\rt.jar]
[Loaded java.lang.String from D:\Program Files\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre\lib\rt.jar]
[Loaded java.lang.reflect.GenericDeclaration from D:\Program Files\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre\lib\rt.jar]
[Loaded java.lang.reflect.Type from D:\Program Files\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre\lib\rt.jar]
[Loaded java.lang.reflect.AnnotatedElement from D:\Program Files\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre\lib\rt.jar]
[Loaded java.lang.Class from D:\Program Files\Genuitec\Common\binary\com.sun.java.jdk.win32.x86_1.6.0.013\jre\lib\rt.jar]
?
?
从以上信息你基本上可以看到一个在执行的时候加载的相关类及jar,明白类在什么时候被加载。以上都是类加载器classloader的工作(这是一份没有小费的工作),getCallerClassLoader()是类加载器的一个私有方法,所以我们是没办法直接调用的,所以在运行中我们应该通过当前 ?类的实例.getClass().getClassLoader(); ? ??getCallerClassLoader()这个方法的调用其实是暗箱操作如果你玩过地下柳河菜或者都求的话,你懂得! 在new一个实例的时候这个方法会被默认调用。
?
在这里我纠正一个常识,静态初始化区域并不是在类第一次载入才会被加载,而是在第一次初始化时被加载并且只有一次。我们测试一下,下面是测试代码:
?
package com.ec.test.classloader.test;public class C {/** * @param args * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException */public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {// TODO Auto-generated method stub//将true改成false在测试一下System.out.println("==========开始载入类B=========="); Class c=Class.forName("com.ec.test.classloader.test.B", true, new C().getClass().getClassLoader()); System.out.println("==========载入类B结束=========="); System.out.println("==========开始实例化B=========="); Object o=c.newInstance(); System.out.println("==========实例化B结束==========="); //new C().getClass().getClassLoader().loadClass("com.ec.test.classloader.test.B"); } }class B{static{System.out.println("test静态初始化区域");}}?
?
下面我们来看一下initialize ?为true的时候输出结果为
?
==========开始载入类B==========
test静态初始化区域
==========载入类B结束==========
==========开始实例化B==========
==========实例化B结束===========
?
?
下面我们来看一下initialize ?为false的时候输出结果为
?
==========开始载入类B==========
==========载入类B结束==========
==========开始实例化B==========
test静态初始化区域
==========实例化B结束===========
?
?
好了通过结果你懂得。 在这里在说一点我们采用new操作的时候会自动初始化和实例化该类,这个暗箱操作也许是我们长久没发现这个问题的原因。
?
?
?
?