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

黑马程序员之类加载器

2013-06-16 11:22 134 查看
------- android培训java培训、期待与您交流! ----------
,类加载器:加载类的工具。

在java程序里,用到一个类,出现类名,JVM首先要把类的字节码加载到内存中,通常类的字节码的原始信息存放在classpath指定目录下,把.classpath加载到硬盘中,再对它进行一些处理,处理成字节码。

把.class文件从硬盘加载进来,然后进行一些处理,这些工作由类加载器完成。

类加载器本身也是java类,因为其他是java类的类加载器本身也要被类加载器加载,显然必须有第一个类加载器不是java类,这正是BootStrap。这个类加载器很特殊,它不是java类,不需要被其他类加载器加载,它是嵌套在JVM内核里的,JVM一启动的时候,它就已经在里面了。它是由C++语言写的一段二进制代码。

二,ExtClassLoaer专门加载JRE/lib/ext/*.jar的jar包。

父亲能够找到,则由父亲加载,否则再由子类加载。

每一个类加载器都会有一个父亲,才能挂到JVM的类树上去,组成树状结构。

,类加载器的委托机制:

①当JVM用到一个类,那么它到底派出哪个类加载器去加载呢?

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

如果类A中引用了类B,JVM将使用加载A的类加载器来加载类B。

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

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

当所有祖宗类加载器没有加载到类,回到发起者类加载器,还加载不了,则抛出ClassNotFoundException,不是再去找发起者类加载器的儿子,因为没有getChild方法,即使有,那有多个儿子,找哪一个呢?

②面试题:能不能自己写一个类叫java.lang.System?可以,写了也是白写,自己写了放在classPath下。但是委托机制会委托给祖宗类,祖宗类就会加载上System类,这样总是使用系统提供的System类,永远不会用到自己写的System类。当然可以自己编写类加载器,绕过系统的类加载器。

,自定义类加载器必须继承一个抽象类ClassLoader。它有一个loadClass方法,这个方法内部会去找它的父类,返回后再执行findClass。子类只需要覆盖findClass方法。

父类ClassLoader-->loadClass/findClass/得到class文件的二进制数据-->使用defineClass方法转换成字节码(也就是class对象)

,模板方法设计模式:父类中规定大体框架,所有子类都需要实现的代码,写在父类中,各个子类需要实现不同的功能的代码,父类中定义为抽象的,具体实现的由子类实现。

,类加载器的一个高级问题分析:

新建一个web工程,建一个servlet,打印当前类的类加载器的名字及它的祖辈类。代码如下:

package cn.itcast.itcastweb.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 {

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()+"<br />");
loader=loader.getParent();
}
out.close();
}

}


部署项目后,运行结果:

org.apache.catalina.loader.WebappClassLoader

org.apache.catalina.loader.StandardClassLoader

sun.misc.Launcher$AppClassLoader

sun.misc.Launcher$ExtClassLoader

可见,当前类是被tomcat自己的类加载器加载的,org.apache.catalina.loader.WebappClassLoader

然后,再做个试验,把刚才的MyServlet导成jar包,放到当前使用的jdk目录下,也就是tomcat使用的jdk目录下,我自己的是C:\Program Files\Java\jdk1.6.0_02\jre\lib\ext\MyServlet.jar,然后再在IE地址栏输入http://localhost:8080/fightingweb/servlet/MyServlet运行,结果报错如下:



如图所示,提示HttpServlet类找不到,分析原因:



先明确一点:如果类A中引用了类B,JVM将使用加载A的类加载器来加载类B。

刚开始,MyServlet是由tomcat自己的类加载器加载的,即用WebAppClassLoader加载的,在加载的过程中发现MyServlet引用了HttpServlet,所以需要加载HttpServlet,WebAppClassLoader类可以成功加载HttpServlet,所以程序正常,没有报错。

后来为什么报错了呢?

后来把MyServlet导出jar包到ext目录下,则使用ExtClassLoader加载,而ExtClassLoader加载HttpServlet的过程中,先委托自己的父类,父类没有找到,所以自己加载,自己又不能加载,所以就报错了。

如何解决呢?

把HttpServlet所在的jar包也放到ext目录下,重启tomcat,就可以了。

运行结果:sun.misc.Launcher$ExtClassLoader
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: