类加载器

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

BootStrapExtClassLoaderAppClassLoader

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

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



类加载器的委托机制

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


首先当前线程的类加载器去加载线程中的第一个类。如果类A中引用了类BJava虚拟机将使用加载类A的类装载器来加载类B

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

每个类加载器加载类时,又先委托给其上级类加载器。当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?

对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的aa.jar包中后,运行结果为ExtClassLoader的原因。


做自己的类加载器 

虚拟机的核心是通过类加载器来加载.class文件,然后进行相应的解析执行。那么我们可以自己做类加载器,手动加载需要的.class以进行解析执行,从而扩展虚拟机的功能。 

网络类加载器子类必须定义方法findClassloadClassData,以实现从网络加载类。下载组成该类的字节后,它应该使用方法defineClass 来创建类实例。 

package cn.hncu.classLoader;

import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;

import org.junit.Test;

import cn.hncu.reflect.Person;
/*注意:::路径名一点要和clathPath下一致
类加载器加载文件时是以classpath为根目录的,然后按照你给出的路径去加载文件。*/
/*
 * 自制类加载器的基本思路:
 * 1、把字节码文件的数据读取(或存放)到一个字节数据buf[]当中
 * 2、利用ClassLoader类中的defineClass()方法把buf[]中的数据生成一个Class对象返回出来。  
 */
public class MyClassLoader  extends ClassLoader{
	//使用指定的二进制名称查找类。此方法应该被类加载器
	//的实现重写,该实现按照委托模型来加载类。在通过父类加载器检查所请求的类后
	//,此方法将被 loadClass 方法调用。默认实现抛出一个 ClassNotFoundException。 
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		//String pathName="G:\\aaa\\cn\\hncu\\Person.class";//这里是路径名字
		byte[] buf=null;
		try {
			//buf = loadData(name);
			ArrayList<Byte> list= loadData2(name);
			Object objs[]=list.toArray();
			buf=new byte[objs.length];
			for(int i=0;i<objs.length;i++){
				buf[i]=(Byte) objs[i];
			}
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		Class<?> c=defineClass("cn.hncu.MyJUinit.A", buf, 0, buf.length);//这里是类名字
		return c;
	}
	//通过IO或网络把字节码数据读取到buf[]当中。进一步地,如果我们自己熟悉字节码的生成格式,那么也可自己用程序生成。
	//本例,我们是把硬盘中的一个外部字节码文件的数据读取到buf[]当中
	private byte[] loadData(String name) throws IOException {
		byte buf[]=new byte[1024];
		byte[] b;
		FileInputStream fin=new FileInputStream(name);
		ByteArrayOutputStream bout=new ByteArrayOutputStream();
		int len=0;
		while ((len = fin.read(buf)) != -1) {
			bout.write(buf, 0, len);
		}
		bout.close();
		b=bout.toByteArray();
		return b;
	}
	@Test
	public void testMyClassLoader() throws ReflectiveOperationException{
		Object obj=Class.forName("cn.hncu.reflect.Person").newInstance();
		Person p=(Person) obj;
		System.out.println(p);
		Object obj2=findClass("G:\\aaa\\cn\\hncu\\reflect\\Person.class").newInstance();//注意路径名一点要和clathPath下一致
		System.out.println(obj);

		//※不同类加载器加载的对象是无法强转---可以理解是不同的生存空间
		Person p2=(Person)obj2;
		System.out.println(p2);
	}
	private ArrayList<Byte> loadData2(String name) throws IOException {
		ArrayList<Byte> list=new ArrayList<Byte>();
		byte[] b;
		FileInputStream fin=new FileInputStream(name);
		int len=0;
		while ((len = fin.read()) != -1) {
			System.out.println("c");
			list.add((byte) len);
		}
		return list;
	}
	
	public Class<?> myFindClass(String name) throws ReflectiveOperationException{
		return findClass(name);
		
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值