有三种类型的Java内置ClassLoader.

            引导类加载器(Bootstrap Class Loader):用于加载jdk内部类。通常加载rt.jar和其它的核心类,例如java.lang.*包类。

            扩展类加载器(Extensions Class Loader):它加载来自于jdk扩展的目录的类,通常是$JAVA_HOME/lib/ext目录。

            系统类加载器(System Class Loader):它加载的当前类路径的类可以被设置的同时,调用 可以使用-cp或者-classpath,命令行选项的程序。

           ClassLoader是分级的,当一个类被加载,那么先找其父类加载器去加载,在运行时,保持这种方式,不断往上一级一级的加载,如果父类加载器没有找到类,再由加载器本身去加载类。

        

java懒加载出错 java加载项_Java

              那么输入以下ClassLoader:

                 System.out.println(String.class.getClassLoader());
             System.out.println(ZipInfo.class.getClassLoader());

              System.out.println(Connection.class.getClassLoader());   

              System.out.println(Gun.class.getClassLoader());

               输出为:

        null
       sun.misc.Launcher$ExtClassLoader@6fd7bd04
       sun.misc.Launcher$AppClassLoader@2ac510e3
       sun.misc.Launcher$AppClassLoader@2ac510e3

          其中Gun 类就是之前声明的枪类。

          可以看出引导类加载器加载的类在jdk的lib/目录下不包括ext目录部分,但是无法得到类加载器,这是为什么呢?不为什么,Java规定的。

          扩展类加载器就是加载jdk里面lib/ext目录下的。ExtClassLoader.

          系统类加载器就是加载我们自己创建的类和引入的三方的库类等。AppClassLoader.

          由此可以看出我们自己定义的所有类,引用的其它库类都是APPclassLoader来加载的。

          Java类的加载就知道了,那么类的静态加载和动态加载是怎么回事呢?

         Java类静态加载,就是我们通常的new 一个对象的时候,这个对象在编译的时候就已经被提供了。

         可以这么理解Java的动态加载。在Java运行时,类生成的对象,没有被预先提供。而去加载这个类。

        

动态编译使用类文件:

        ClassLoader加载的类是.class文件到内存。那么从.java文件编译到.class。我们怎么主动去做?把它编译成.class文件。Java给提供了一些方法。

         首先我们创建一个Dagger类:

  

public class Dagger {

     
     private String name;
     private String address;
     public String getName() {
         return name;
     }
     public void setName(String name) {
         this.name = name;
     }
     public String getAddress() {
         return address;
     }
     public void setAddress(String address) {
         this.address = address;
     }
 }
并放到D盘的sun目录下;

        

java懒加载出错 java加载项_Java_02

            JavaCompiler complier = ToolProvider.getSystemJavaCompiler();     
            StandardJavaFileManager filemanager =   
                    complier.getStandardFileManager(null, null, null);  
            Iterable it = filemanager.getJavaFileObjects("D:\\sun\\Dagger.java");    
            CompilationTask task = complier.getTask(null, filemanager, null, null, null, it);  
            task.call();  //
            try {
                filemanager.close();
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            } 
           执行完这些代码后,会发现多了Dagger.class:

     

java懒加载出错 java加载项_加载_03

          那么我们怎么使用这个Dagger.class呢?

          我们的.java类文件不是在项目的库中或者项目的java源目录中,而是在其它目录,其它地方。比如:项目在D盘创建,而我需要的另一个.java文件在C盘,那么怎么用C盘的这个类呢?

          由我们的类加载器完成:

          

File file=new File("D:\\sun\\");
                
              URL url=null;
             try {
                 url = file.toURL();
             } catch (MalformedURLException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
              URLClassLoader urlClassLoader=new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());
                 Class<?> loadClass = urlClassLoader.loadClass("Dagger");
                 Object newInstance = loadClass.newInstance();
                 Field declaredField = loadClass.getDeclaredField("name");
                 declaredField.setAccessible(true);
                 declaredField.set(newInstance, "瑞士军刀");
                 Method method = loadClass.getMethod("getName");
                 Object invoke = method.invoke(newInstance);
                 System.out.println(invoke);             注意:里面的try cac

he太多,省略。

             输出为:

            瑞士军刀

             可以看出,我们可以直接调用来自于各个地方的.class类文件,包括从网络中获取的,也就是说,在更新程序的时候,只需要更新几个类的这种,就简单的多了,程序运行时就可以升级。不必重启程序。

             显然,我们需要的不仅仅是一个或者几个类 的改变。会是一个jar包的形式。

动态加载jar包

            新建一个类:

          

package com.test2.util;

 public class Gun {
     private String name;
     private int bullet;
     private String address;
     public String getName() {
         return name;
     }
     public void setName(String name) {
         this.name = name;
     }
     public int getBullet() {
         return bullet;
     }
     public void setBullet(int bullet) {
         this.bullet = bullet;
     }
     public String getAddress() {
         return address;
     }
     public void setAddress(String address) {
         this.address = address;
     }
     @Override
     public String toString() {
         // TODO Auto-generated method stub
         return "{"+name+","+bullet+","+address+"}";
     }
     
 }

        把这个包打成jar包的形式,暂且命名test2.jar.放到d盘的sun目录下。

        那么引用jar包

          

File file=new File("D:\\sun\\test2.jar");
                
              URL url=null;
             try {
                 url = file.toURL();
             } catch (MalformedURLException e) {
                 // TODO Auto-generated catch block
                 e.printStackTrace();
             }
              URLClassLoader urlClassLoader=new URLClassLoader(new URL[]{url}, Thread.currentThread().getContextClassLoader());
         
                 Class<?> loadClass = urlClassLoader.loadClass("com.test2.util.Gun");
                 
                 Object newInstance = loadClass.newInstance();
                 Field name = loadClass.getDeclaredField("name");
                 Field bullet=loadClass.getDeclaredField("bullet");
                 Field address=loadClass.getDeclaredField("address");
                 name.setAccessible(true);
                 bullet.setAccessible(true);
                 address.setAccessible(true);
                 name.set(newInstance, "手枪");
                 bullet.set(newInstance, 20);
                 address.set(newInstance, "美国");
                 Method method = loadClass.getMethod("toString");
                 Object invoke = method.invoke(newInstance);
                 System.out.println(invoke);

             注意:里面的try cache太多,省略。

              执行这段代码输出: