黑马程序员--类加载器及其委托机制

----------- android培训、java培训、java学习型技术博客、期待与您交流! ------------

1.类加载器

①Java虚拟机中可以安装多个类加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader,AppClassLoader。

②类加载器也是Java类,因为其他是Java类得类加载器本身也要被雷加载器加载,显然必须有第一个类加载器不是Java类,这正是BootStrap类。

③Java虚拟机中的所有类装载器采用父子关系的树形结构进行组织,在实例化每个类装载器对象时,需要为其指定一个父级类装载器对象或者默认采用系统类装载器为其父级类加载器。

    System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
    System.out.println(System.class.getClassLoader().getClass().getName());    //编译出错
    System.out.println(System.class.getClassLoader());//结果为null,指的是bootStrap加载的

系统默认的三个主要类加载器,它们之间的父子关系可以用下面程序看到:

  ClassLoader loader = ClassLoaderTest.class.getClassLoader();
  while(loader != null) {
   System.out.println(loader.getClass().getName());     //返回结果为AppClassLoader
   loader = loader.getParent();     //获得父级类加载器
  }
  System.out.println(loader);

打印的结果为:

sun.misc.Launcher$AppClassLoader
sun.misc.Launcher$ExtClassLoader
null

值得注意的是,最后打印出来的才是根结点。

类加载器之间的父子关系和管辖范围如下(下一级是由上一级加载的):

BootStrap-------->JRE/lib/rt.jar

ExtClassLoader-------->JRE/lib/ext/*.jar

AppClassLoader-------->CLASSPATH指定的所有jar或目录

2.类加载器的委托机制

当Java虚拟机要加载一个类时,到底配出哪个类加载器去加载呢?

首先当前的线程的类加载器去加载线程中的第一个类。

如果类A引用了类B,Java虚拟机将使用加载类A得类加载器来加载类B。

还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。

每个类加载器加载类时,又先委托给其上级类加载器。

当所有祖宗类加载器没有加载到类,会带发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild()方法(在Java中只有getParent()方法),即使有,也有多个儿子,找哪一个呢?

3.自定义类加载器

自定义的类加载器必须继承ClassLoader

注意loadClass方法、findClass方法和defineClass方法的使用:

package cn.itcast.day2;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;

public class MyClassLoader extends ClassLoader{

 /**
  * @param args
  */
 public static void main(String[] args) throws Exception {
  // TODO Auto-generated method stub
  String srcPath = args[0]; //源路径
  String destDir = args[1]; //目标目录
  FileInputStream fis = new FileInputStream(srcPath);
  String destFileName = srcPath.substring((srcPath.lastIndexOf('\\'))+1);
  String destPath = destDir + "\\" + destFileName;
  FileOutputStream fos = new FileOutputStream(destPath);
  cypher(fis,fos);
  fis.close();
  fis.close();
  
 }
 
 private static void cypher(InputStream is,OutputStream os) throws Exception { //加密算法
  int b = -1;
  while((b = is.read())!= -1) {
   os.write(b ^ 0xff);
  }
 }
 
 private String classDir;
 
 @Override
 protected Class<?> findClass(String name) throws ClassNotFoundException {
  // TODO Auto-generated method stub
  String classFileName = classDir + "\\" + name + ".class";
  try {
   FileInputStream fis = new FileInputStream(classFileName);
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   cypher(fis,baos);
   System.out.println("aaa");
   fis.close();
   byte[] bytes = baos.toByteArray();
   defineClass(bytes, 0, bytes.length);
  } catch (Exception e) {
   // TODO Auto-generated catch block
   e.printStackTrace();
  }
  
  return super.findClass(name);
 }
 
 public MyClassLoader() {
  
 }
 
 public MyClassLoader(String classDir) {
  this.classDir = classDir;
 }

}

自定义的类加载器,虽然原理比较简单,但是代码写起来还是比较复杂的,我还是有些地方没有弄懂,特别是当遇到错误时,该怎么去解决,通过对这次类加载器的学习,我感触颇深。以后会更加努力学习,不断提高自己的能力,争取学会更多的知识,为今后走入社会打下夯实的基础……

 

 

 

 

 

 

----------------------- android培训、java培训、java学习型技术博客、期待与您交流! ----------------------

详情请查看:http://edu.csdn.net/heima

 

你可能感兴趣的:(java,android,虚拟机,exception,String,ClassLoader)