类加载器

来源:互联网 发布:史蒂夫纳什生涯数据 编辑:程序博客网 时间:2024/06/14 02:59

作用:当程序用到某个类中,由类加载器将类的字节码加载进内存。
      
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 blocke.printStackTrace();}}private String classPath;@Overrideprotected Class<?> findClass(String name) throws ClassNotFoundException {// TODO Auto-generated method stubtry {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 blocke.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 stubtry {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 blocke.printStackTrace();} catch (InstantiationException e) {// TODO Auto-generated catch blocke.printStackTrace();} catch (IllegalAccessException e) {// TODO Auto-generated catch blocke.printStackTrace();}}}













原创粉丝点击