您的位置:首页 > 职场人生

黑马程序员---java基础加强---类加载器

2014-06-16 13:43 323 查看
----------- android培训java培训、java学习型技术博客、期待与您交流! -----------

一 类加载器

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

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

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

类加载器之间的斧子关系和管辖范围

BootStrap——JRE/lib/rt.jar
|
ExtClassLoader——JRE/lib/ext/*.jar
|

System classLoader——AppClassLoader——CLASSPATH指定的所有jar或目录

/ \

MyClassLoader ItcastClassLoader——传播智客制定的特殊目录



二 类加载器的委托机制

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

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

如果类A中引用了类B,java虚拟机将使用加载类A的类加载器来加载类B

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

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

当所有祖宗类加载器没有加载到类(先祖后父再自己),回到发起者来加载器,还加载不了,则抛出ClassNotFoundException,,不是再去找发起者类加载器的子类加载器,因为没有getChild方法。

分析:由发起者父类加载,而不是由发起者子类去加载,原因一:发起者可能有多个子类,那么不确定由哪个子类去加载,而发起者只有一个父类,因此可以确定由父类加载器去加载。原因二:由父类加载器加载那么产生一份字节码文件,而由多个子类加载,有可能出现多份相同字节码,浪费内存空间。

三 自定义类加载器

知识讲解:

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

loadClass方法与findClass方法

defineClass方法

父类--loadClass/findClass--得到class文件的转换成字节码--definClass(),简单的说就是,继承ClassLoader,覆盖findClass()方法,findClass()中用definClass()方法将字节数组转为字节码。(loadClass作用是逐级委托父类加载器去加载类,因此不用覆盖)

编程步骤

编写一个对文件内容进行简单加密的程序。

编写了一个自己的类加载器,可实现对加密过的类进行装载和解密

编写一个程序调用类加载器加载类,在源程序中不能用该类名定义引用变量,因为编译器无法识别这个类。程序中可以处理使用ClassLoader.load方法之外,还可以使用设置线程的上下文类加载器或者系统类加载器,然后再使用Class.forName

实验步骤:

对不带包名的class文件进行加密,加密结果存放到另一个木,例如java MyClassLoader MyTest.class F:\itcast

运行加载类的程序时,结果能够被正常加载,但打印出来的类加载器名称为AppClassLoader:java MyClassLoader MyTest F:\itcast

用加密后的类文件替换CLASSPATH环境下的类文件,再执行上一步操作就出问题了,错误说明是AppClassLoader类加载器装载失败

删除CLASSPATH环境下定的类文件,再执行上一步操作就可以了。





编写一个能打印出自己的类加载器名称和当前类加载器的斧子结构关系链的MyServlet,正常发布后,看到打印结果为WebAppClassLoader

把MyServlet.class文件打成jar包,放到ext目录下,重启tomcat,发现找不到HttpServlet错误

把tomcat中的servlet.jar也放到ext目录中,问题解决,打印结果ExtclassLoader

package cn.itcast1.itcastweb1.web.servlets;

import java.io.IOException;

import java.io.PrintWriter;

import javax.servlet.ServletException;

import javax.servlet.http.HttpServlet;

import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;

public class MyServlet extends HttpServlet {

/**

* The doGet method of the servlet. <br>

*

* This method is called when a form has its tag value method equals to get.

*

* @param request the request send by the client to the server

* @param response the response send by the server to the client

* @throws ServletException if an error occurred

* @throws IOException if an error occurred

*/

public void doGet(HttpServletRequest request, HttpServletResponse response)

throws ServletException, IOException {

response.setContentType("text/html");

PrintWriter out = response.getWriter();

ClassLoader loader = this.getClass().getClassLoader();

while(loader != null)

{

out.println(loader.getClass().getName());

loader = loader.getParent();

}

out.close();

}

}

----------- android培训java培训、java学习型技术博客、期待与您交流! -----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: