现在的位置: 首页 > 综合 > 正文

Java_类加载器ClassLoader

2013年11月24日 ⁄ 综合 ⁄ 共 3967字 ⁄ 字号 评论关闭

1.类加载器简述
      (1).类加载器功能

            把类从静态的.class文件中,经过虚拟机过滤而装入主存而成为字节码文件!
      (2).类加载器载入方式
            1).预先载入
                  基础类库是一次性载入的,因为基础库中包含java程序执行所必需的类,只是在起始是需要时间!
            2).需求载入
                  自己编写的类只会在用到的时候才载入,仅仅声明一个类型是不会被加载的,通过实例化或者这四种方式>>才会加载进主存。如果该类有父类,载入该类之前应确保父类加载,即父类是在子类之前加载,同样遵循委托机制!
2.类加载器详述
      (1).类加载器的加载过程

            虚拟机启动后,会完成一些初始化动作,在这过程中产生第一个类加载器Bootstrap Loader,Bootstrap Loader是由C++编写的,这个类加载器还会加载其它的类加载器,即sun.msic.Launcher.java中的ExtClassLoader(内部类)编译成Launcher$ExtClassLoader.class,并设定其parent为null,代表其父类加载器为Bootstrap
Loader。然后Bootstrap Loader还会加载该java文件Launcher.java中的AppClassLoader编译成Launcher$AppClassLoader.class,并设定其parent为之前产生的ExtClassLoader实例。
      注意:Launcher$ExtClassLoader.class与Launcher$AppClassLoader.class都是由Bootstrap Loader所载入,所以parent和由那个类加载器载入没有关系,可以通过下面代码检验!

	Person p = new Person(1);
	System.out.println(p.getClass().getClassLoader());//sun.misc.Launcher$AppClassLoader@fb56b1
	System.out.println(p.getClass().getClassLoader().getClass().getClassLoader());//null
	/*
	 * 得到验证AppClassLoader加载器的加载器是null即Bootstrap Loader,parent不能真实反映
	 * 只是AppClassLoader在加载后的Class对象中,Bootstrap Loader修改了该parent值为ExtClassLoader
	 */

      (2).类加载器的类别
            jvm中默认的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader
            1).Bootstrap ClassLoader
                  用C++编写的,在Java中看不到它,是null,是JVM自带的类装载器,负责加载java基础类,即目录/lib/rt.jar,可以通过
System.getProperty("sun.boot.class.path")
            2).Extension ClassLoader
                  负责加载java扩展类,即目录/lib/ext下的jar和class,可以通过System.getProperty("java.ext.dirs")来取得
            3).App ClassLoader
                  负责加载当前java应用的classpath中的所有类和JAR,可以通过 System.getProperty("java.class.path")来取得,其加载该加载器的加载器是Bootstrap ClassLoader,但是Bootstrap ClassLoader修改了该parent值
      注意:AppClassLoader和Bootstrap Loader只会搜索上述指定路径下的文件,因为AppClassLoader和ExtClassLoader在整个虚拟机中只存在一份,一旦建立了,其内部所参考的搜索路径将不再改变,即使我们在程序里利用System.setProperty()来改变系统参数的内容,仍然无法更改搜索路径。
3.类加载器的委托机制
      (1).首先是当前线程的类加载器去加载线程中的第一个类。
      (2).如果类A中引用了类B,Java虚拟机将使用加载类A的类加载器来加载类B。
      (3).还可以直接调用ClassLoader.loadClass()方法来指定某个类加载器去加载某个类。
       java.lang.System在BootStrap中最先加载,但是可以写一个类加载器来加载我们自己写的java.lang.System类,即该加载器 loadClass方法不委托。
4.自定义类加载器
      (1).准备的class
            MyLoader,自定义的类加载器,继承了ClassLoader
            InterTest接口,用于供Worker实现,抽象了Worker的方法(注意重要性,在Test中得到class是用于强转)
            Worker类,需要自定义的类加载器加载
            Test,用于测试类加载器
      (2).自定义类加载器实现过程
            1).调用 findLoadedClass(String) 来检查是否已经加载类。
            2).在父类加载器上调用 loadClass 方法。如果父类加载器为 null,则使用虚拟机的内置类加载器。 
            3).调用 findClass(String) 方法查找类。
      (3).代码实现

/*
 * @author strawberry2013
 * @fie Test.java
 * 测试类加载器
 */
public class Test {
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
		
		Class clazz = new MyLoader().loadClass("Worker");	//通过类加载器加载任一路径下的正确编译的class文件
		InterTest test = (InterTest)clazz.newInstance();	//接口强转的重要
		/*
		 * 此处强转应该使用该类的父类或者接口,其中clazz得到的是Worker的字节码文件
		 * Worker test = (Worker)clazz.newInstance(); 强转的Worker默认加载不存在该字节码文件,故发生错误
		 */
		test.work();
	}
}
/*
 * 类加载器
 * @file MyLoader.java
 */
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;

public class MyLoader extends ClassLoader{

	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		String path = "E:/Android/Project/Test/"+name+".class";//欲加载一个任一路径下的class文件
		FileInputStream fi = null;
		ByteArrayOutputStream bt = null;
		try {
			fi = new FileInputStream(path);
			bt = new ByteArrayOutputStream();
			int p = 1;
			while((p=fi.read()) != -1){
				bt.write(p);	//将输入流写入内存流
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally{
			try {
				fi.close();
				bt.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		byte[] bytes = bt.toByteArray();	//将内存中的流转换为byte
		return defineClass(bytes, 0, bytes.length);//生成内存中的字节码
	}
	@Override
	public Class<?> loadClass(String name) throws ClassNotFoundException {
		// TODO Auto-generated method stub
		return super.loadClass(name);	//如果不想使用委托机制,可以修改这个函数
	}
}
/*
 * @file InterTest.java
 * 供Worker实现,覆写方法
 */
public interface InterTest {
	public void work();
}
/*
 * @file Worker.java
 */
public class Worker implements InterTest{
	public void work(){
		System.out.println("work........~~..");
	}
}

抱歉!评论已关闭.