《java深度历险》------深入类别载入器
Class.forName函数有两个重载,一个是只有一个参数的:public static Class forName(String className) 另一个是有三个参数的:public static Class forName(String name,boolean initialize,ClassLoader loader) 这两个方法最后都调用了原生方法(native method):private static native Class forName0(String name,boolean initialize,ClassLoader loader) throws ClassNotFoundException; 只有一个参数的forName()方法最后调用的是: forName0(className,true,ClassLoader.getCallerClassLoader());注意:ClassLoader.getCallerClassLoader是private的,我们写的应用程序无法调用 三个参数的forName()方法最后调用的是: forName0(name,initialize,loader); 对于三个参数的forName方法,为了获得类别载入器,可以这样用:
Office off = new Office() ; Class c = Class.forName(args[0],true,off.getClass().getClassLoader()) ; Object o = c.newInstance() ;
也可以这样获得ClassLoader:Office.class.getClassLoader();其中Office是类名 在大多数情况下,静态初始化区块是在类第一次加载的时候被调用,且仅调用一次,但是如果对于三个参数的Class.forName方法,如果第二个参数为false的时候,静态初始化区块是在类第一次被实例化时才会被调用一次且只调用一次。 显式地使程序达到动态性的另外一种方法是直接使用类装载器 每一个类的实例都有一个getClass()方法,每一个类也都有一个名为class的成员,它们都指向一个Class类的实例,这个Class类的实例有一个getClassLoader();方法,以获得装载该类的类装载器。 使用类装载器装载类的代码如下:
Class cb = Office.class ;   
System.out.println("類別準備載入") ;   
ClassLoader loader = cb.getClassLoader() ;   
Class c = loader.loadClass(args[0]) ;                 
System.out.println("類別準備實體化") ;   
Object o = c.newInstance() ;  
Word word=(Word)o;
System.out.println(word.getClass()==Word.class);
从上面最后一行代码的输出结果来看,实例的getClass()方法获得的Class对象与Word类的Class属性获得的Class对象是同一个对象。 另外,直接使用ClassLoader类的loadClass()方法来装载类只是把类载入内存,并不调用类的静态初始化区块,这种情况与使用Class类的带三个参数的forName()方法时,第二个参数传入false是相同的。 可以使用自定义的类装载器载入类 代码如下:
  URL u = new URL("file:/d:/my/lib/") ;   
  URLClassLoader ucl = new URLClassLoader(new URL[]{ u }) ; 
  Class c = ucl.loadClass(args[0]) ; 
虽然ucl这个类装载器有一个URL但是代码中写的是由它来装载类,但是实际上类到底由哪个类装载器来装载,和类装载器的阶层体系有关,如果其父装载器在其搜索目录中可以找到相应的类,则会由其父装载器来装载。 类装载器的阶层体系 java虚拟机起动,完成初始化工作后,就会产生第一个类别载入器,Bootstrap Loader,它是由C++所写成的。它将载入定义在sun.misc命名空间下的Launcher.java中的ExtClassLoader,并设定其Parent为null,随后Bootstrap Loader继续载入位于sun.misc命名空间下的Launcher.java中的AppClassLoader(系统载入器),并设定其Parent为之前产生的ExtClassLoader。除了Bootstrap Loader,其他所有类装载器都是由Bootstrap Loader载入的。 AppClassLoader的搜索路径默认为.即当前目录,如果java命令使用-classpath选项,可改变AppClassLoader的搜索路径,如没有该选项,就会搜索环境变量classpath,如果二者同时存在,则以-classpath为准,两者没有叠加效果。 可这样打印:System.getProperty("java.class.path"); ExtClassLoader的情况类似,可这样打印:System.getProperty("java.ext.dirs"); Bootstrap Loader的搜索路径可通过查询系统属性sun.boot.class.path来查看。 AppClassLoader与Bootstrap Loader会搜索它们指定的位置或JAR档,ExtClassLoader会搜索其搜索目录下所有JAR档及目录。 Bootstrap Loader的搜索路径无法改变,而AppClassLoader与ExtClassLoader的搜索路径只可以在初始化的时候更改,程序运行以后无从更改。 类装载器有类的装载需求时,会首先查询其父载入器载入,如果其父载入器找不到该类,才由自己依照自己的搜索路径搜索类。如果某个类由Bootstrap Loader载入了,这个类内部,有新的类装载需求,仍然会由Bootstrap Loader来装载。
 
                    
                     
                    
                 
                    
                 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号