类加载器

作用:当程序用到某个类中,由类加载器将类的字节码加载进内存。
      
JAVA虚拟机中可以安装多个加载器,系统默认三个主要类加载器,每个类负责加载特定位置的类:BootStrap,ExtClassLoader, AppClassLoader


xxx.class.getClassLoader.getClass( ).getName( );//获取某个类的类加载器的名称。
但是调用JAVA提供的类是由BootStrap加载器加载,底层加载器。用get.ClassLoader返回的是空。
      
类加载也是一个java类,因为其它是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是JAVA类的,这正是BootStrap,由C++编写的。
 
类加载器之间的父子关系和管辖范围
BootStap                             JRE/lib/rt.jar(JAVA提供的类都在rt.jar包里)
ExtClassLoader                    JRE/lib/ext/*.jar(ext扩展jar包存放目录,如果把自己写的类导成jar包放到此目录下。会被ExtClassLoader加载器加载)
AppClassLoader                  ClassPath指定的所有jar或目录
(优先级问题:先父后子)
自定义类加载器,需要继承ClassLoader类,构造方法中需指定加载类的父类。默认有。
 
 
类加载器的委托机制
 
当Java虚拟机要加载一个类时,到底派出哪个类加载器去加载呢?
1.    首先当前线程的类加载器去加载线程中的第一个类。
Thread类中有一个方法:setContextClassLoader(ClassLoader cl)。
2.    如果类A中引用了类B,Java虚拟机将使用加载类A的类装载器来加载类B。
3.    还可以直接调用ClassLoader.loadClass( )方法来指定某个类加载器去加载某个类。
 
每个类加载器加载类时,又先委托给其上级类加载器。
1.    当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛ClassNotFooundException,不是再去找发起者类加载器的子类了,因为没有getChild方法,即使有,那有多个子类,找哪一个呢?
2.    对着类加载器的层次结构图和委托加载原理,解释先前将ClassLoaderTest输出成jre/lib/ext目录下的itcast.jar包中后,运行结果为ExtClassLoader的原因。
 
面试题:我们可以写一个java.lang.System包
答:通常是不可以的,因为如果我写一个System类放到ClassPath目录下,ClassPath目录下的类都是由AppClassLoader加载的,AppClassLoader会委托祖宗类,System在祖宗类中存在,会加载。所以根本不可能加载我的这个System类。不过有一种办法,就是我自己写一个类加载器,而这个类加载器不用委托祖宗类。
 
1.知识讲解:
 自定义的类加载器的必须继承ClassLoader抽象类
 loadClass()方法与findClass()方法,loadClass() 方法是去委托父类,我们自己写加载类只要覆盖findClass方法。
 defineClass(String name)方法:将得到的class文件转换成字节码
2.编程步骤:
 编写一个对文件内容进行简单加密的程序。
 编写了一个自己的类装载器,可实现对加密过的类进行装载和解密。
 编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类。程序中可以除了使用ClassLoader.load方法之外,还可以使用设置线程的上下文类加载器或者系统类加载器,然后再使用Class.forName。
3.实验步骤:
 对不带包名的class文件进行加密,加密结果存放到另外一个目录,例如: java MyClassLoader MyTest.class F:\itcast
 运行加载类的程序,结果能够被正常加载,但打印出来的类装载器名称为AppClassLoader:java MyClassLoader MyTest F:\itcast
 用加密后的类文件替换CLASSPATH环境下的类文件,再执行上一步操作就出问题了,错误说明是AppClassLoader类装载器装载失败。
 删除CLASSPATH环境下的类文件,再执行上一步操作就没问题了。

MyClassLoader.java

package cn.test;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
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 sourceFilePath = args[0];
	// String targetDir = args[1];
	// String myPath = MyClassLoader.class.getResource("").getPath();
	// String[] path = myPath.split("bin");
	// String targetFilePath =
	// path[0]+targetDir+"\\"+sourceFilePath.substring(sourceFilePath.lastIndexOf('\\')+1);
	//
	// InputStream is = new FileInputStream(sourceFilePath);
	// OutputStream os = new FileOutputStream(targetFilePath);
	//
	// encrypt(is,os);
	// }

	public static void encrypt(InputStream is, OutputStream os) {

		int by = -1;
		try {
			while ((by = is.read()) != -1) {
				os.write((byte) by * 0xff);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	private String classPath;

	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		// TODO Auto-generated method stub
		try {
			InputStream is = new FileInputStream(classPath + File.separator
					+ name + ".class");
			ByteArrayOutputStream baos = new ByteArrayOutputStream();

			encrypt(is, baos);

			byte[] bytes = baos.toByteArray();

			return defineClass(bytes, 0, bytes.length);

		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return super.findClass(name);
	}

	public MyClassLoader() {
		// TODO Auto-generated constructor stub
	}

	public MyClassLoader(String classPath) {

		this.classPath = classPath;
	}
}

MyClassTest.java 测试类

package cn.test;

public class MyClassTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		try {
			Class clazz = new MyClassLoader("myclasslib").loadClass("MyClass");
			Object obj = clazz.newInstance();
			System.out.println(obj.toString());

			System.out.println("====================================");

			ClassLoader clazzLoader = obj.getClass().getClassLoader();
			while (clazzLoader != null) {
				System.out.println(clazzLoader.getClass().getName());
				clazzLoader = clazzLoader.getParent();
			}
			if (clazzLoader == null)
				System.out.println("BootStrap");

		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InstantiationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}













你可能感兴趣的:(类加载器)