java类的加载

打印Thread.currentThread().getContextClassLoader(),显示如下:
sun.misc.Launcher$AppClassLoader@19821f
这个加载器是系统类加载器。ClassLoader.getSystemResourceAsStream("com/config.xml")使用的就是系统类加载器定位资源的。


    //JDK1.6,java.lang.ClassLoader的 loadClass(String name,  boolean  resolve)方法的源码
protected   synchronized  Class <?>  loadClass(String name,  boolean  resolve)
    
throws  ClassNotFoundException
    {
    
//  First, check if the class has already been loaded
    Class c  =  findLoadedClass(name);
    
if  (c  ==   null ) {
        
try  {
        
if  (parent  !=   null ) {
           //
如果parent不为null,则调用parent的loadClass进行加载 
            c  =  parent.loadClass(name,  false );
        } 
else  {
           //
parent为null,则调用BootstrapClassLoader进行加载
            c  =  findBootstrapClassOrNull(name);
        }
        } 
catch  (ClassNotFoundException e) {
                
//  ClassNotFoundException thrown if class not found
                
//  from the non-null parent class loader
         }
       
if  (c  ==   null ) {
            
//  If still not found, then invoke findClass in order to find the class.
            //
如果仍然无法加载成功,则调用自身的findClass进行加载
            c  =  findClass(name);
        }
    }
    
if  (resolve) {
        resolveClass(c);
    }
    
return  c;
    }

java中共有三种类型的类加载器:
    1、引导(bootstrap)类加载器(用来加载java API类),例如加载java.lang.String类
    2、扩展类加载器(就是sun.misc.Launcher$ExtClassLoader,用来加载jre\lib\ext目录下的jar包)
    3、系统类加载器(就是sun.misc.Launcher$AppClassLoader,主要用来加载CLASSPATH设置目录中的Class)

创建一个URLClassLoader,发现其父加载器(parent,注意不是父类)的类型为sun.misc.Launcher$AppClassLoader,而sun.misc.Launcher$AppClassLoader和sun.misc.Launcher$ExtClassLoader的父类都是URLClassLoader。AppClassLoader的父加载器是ExtClassLoader,ExtClassLoader的父加载器为null,即bootstrap类加载器。

类加载有个双亲委托模式,
AppClassLoader的父加载器是ExtClassLoader ,ExtClassLoader 的父加载器是bootstrap classloader,bootstrap 是C++写的类加载器,会负责加载java核心类库,就是jre/lib/rt.jar
ExtClassLoader会加载扩展类库,就是jre/lib/ext下的库。

双亲委托模式就是子加载器会先委托父加载器加载,父加载器加载不了子加载器才加载,
这样做避免了重复加载,也加强了java的安全了,防止了恶意加载器去加载核心库。

String name  =   " com.domain.Account " ;
            
            URL url1 
=   new  URL( " file:/D:/workspace/test/bin/ " );
            ClassLoader cl 
=   new  URLClassLoader( new  URL[] { url1 });
            Class c1 
=  cl.loadClass(name);
            
            URL url2 
=   new  URL( " file:/D:/workspace/test/bin " );
            ClassLoader cl2 
=   new  URLClassLoader( new  URL[] { url2 });
            Class c2 
=  cl2.loadClass(name);
            
            System.out.println(c1
== c2); // 返回true,原因是都是用系统类加载器AppClassLoader 加载的

注意:
1,在类A中使用Class.forName加载类B,那么加载类A的类加载器将会用于加载类B,这样两个类的类加载器是同一个。
2,Class.forName("")和classLoader.load("")的区别主要是前者会做初始化,后者不会。见jdk注释: A call to forName("X") causes the class named X to be initialized.  自己分别用两种方式装载一个带静态代码的类就知道了。jdbc需要通过Class.forName("")的方式来装载JDBC驱动程序(例如 Class.forName("com.mysql.jdbc.Driver"),之所以用Class.forName而没有用 ClassLoader.load(),就是因为需要JVM完成Driver的初始化工作,而不仅仅是装载),然后通过一个统一的工厂类 Java.sql.DriverManager来取得数据库连接,并执行各种操作。 Class.forName("")不仅load class而且还保证resolve这个class,包括常量池解析,类初始化。。。这样JDBC驱动使用这个方法,才能保证类里的静态方法执行,一般驱动类的静态方法会向DriverManager注册自己,如果用classloader.load("")就不一定会resolve这个class,也就不能保证注册驱动类!
看了com.mysql.jdbc.Driver类的源码,静态代码就一句:java.sql.DriverManager.registerDriver(new com.mysql.jdbc.Driver())
3,

参考
1)java系统类加载器AppClassLoader之浅谈 http://blog.sina.com.cn/s/blog_4db6a3f101000do1.html
2)java类加载原理分析 http://gongmingwind.javaeye.com/blog/338366
3)解读ClassLoader http://www.javaeye.com/topic/83978
4)http://xyiyy.javaeye.com/blog/362107

Retrotranslator是一个Java字节码转换工具。它能够把用JDK5.0编译的Java Class转换成可运行在JVM1.4

你可能感兴趣的:(java类的加载)