读者可能在这里有疑问,父类有那么多方法,为什么偏偏只重写findClass方法?
  因为JDK已经在loadClass方法中帮我们实现了ClassLoader搜索类的算法,当在loadClass方法中搜索不到类时,loadClass方法会调用findClass方法来搜索类,所以我们只需重写该方法即可。如没有特殊的要求,一般不建议重写loadClass搜索类的算法。下图是API中ClassLoader的loadClass方法:

  示例:自定义一个NetworkClassLoader,用于加载网络上的class文件
  package classloader;
  import java.io.ByteArrayOutputStream;
  import java.io.InputStream;
  import java.net.URL;
  /**
  *加载网络class的ClassLoader
  */
  public class NetworkClassLoader extends ClassLoader{
  private String rootUrl;
  public NetworkClassLoader(String rootUrl){
  this.rootUrl=rootUrl;
  }
  @Override
  protected Class<?>findClass(String name)throws ClassNotFoundException{
  Class clazz=null;//this.findLoadedClass(name);//父类已加载
  //if(clazz==null){//检查该类是否已被加载过
  byte[]classData=getClassData(name);//根据类的二进制名称,获得该class文件的字节码数组
  if(classData==null){
  throw new ClassNotFoundException();
  }
  clazz=defineClass(name,classData,0,classData.length);//将class的字节码数组转换成Class类的实例
  //}
  return clazz;
  }
  private byte[]getClassData(String name){
  InputStream is=null;
  try{
  String path=classNameToPath(name);
  URL url=new URL(path);
  byte[]buff=new byte[1024*4];
  int len=-1;
  is=url.openStream();
  ByteArrayOutputStream baos=new ByteArrayOutputStream();
  while((len=is.read(buff))!=-1){
  baos.write(buff,0,len);
  }
  return baos.toByteArray();
  }catch(Exception e){
  e.printStackTrace();
  }finally{
  if(is!=null){
  try{
  is.close();
  }catch(IOException e){
  e.printStackTrace();
  }
  }
  }
  return null;
  }
  private String classNameToPath(String name){
  return rootUrl+"/"+name.replace(".","/")+".class";
  }
  }
  测试类:
  package classloader;
  public class ClassLoaderTest{
  public static void main(String[]args){
  try{
  /*ClassLoader loader=ClassLoaderTest.class.getClassLoader();//获得ClassLoaderTest这个类的类加载器
  while(loader!=null){
  System.out.println(loader);
  loader=loader.getParent();//获得父加载器的引用
  }
  System.out.println(loader);*/
  String rootUrl="http://localhost:8080/httpweb/classes";
  NetworkClassLoader networkClassLoader=new NetworkClassLoader(rootUrl);
  String classname="org.classloader.simple.NetClassLoaderTest";
  Class clazz=networkClassLoader.loadClass(classname);
  System.out.println(clazz.getClassLoader());
  }catch(Exception e){
  e.printStackTrace();
  }
  }
  }
  打印结果:

  下图是我机器上web服务器的目录结构:

  目前常用web服务器中都定义了自己的类加载器,用于加载web应用指定目录下的类库(jar或class),如:Weblogic、Jboss、tomcat等,下面我以Tomcat为例,展示该web容器都定义了哪些个类加载器:
  1、新建一个web工程httpweb
  2、新建一个ClassLoaderServletTest,用于打印web容器中的ClassLoader层次结构

  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 ClassLoaderServletTest 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.write(loader.getClass().getName()+"<br/>");
  loader=loader.getParent();
  }
  out.write(String.valueOf(loader));
  out.flush();
  out.close();
  }
  public void doPost(HttpServletRequest request,HttpServletResponse response)
  throws ServletException,IOException{
  this.doGet(request,response);
  }
  }
  3、配置Servlet,并启动服务
  <?xml version="1.0"encoding="UTF-8"?>
  <web-app version="2.4"
  xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
  http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
  <servlet>
  <servlet-name>ClassLoaderServletTest</servlet-name>
  <servlet-class>ClassLoaderServletTest</servlet-class>
  </servlet>
  <servlet-mapping>
  <servlet-name>ClassLoaderServletTest</servlet-name>
  <url-pattern>/servlet/ClassLoaderServletTest</url-pattern>
  </servlet-mapping>
  <welcome-file-list>
  <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
  </web-app>
  4、访问Servlet,获得显示结果