深入理解java:1.1.类加载器

Posted 张俊鸿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解java:1.1.类加载器相关的知识,希望对你有一定的参考价值。

从java的动态性到类加载机制

 

我们知道,Java是一种动态语言。

那么怎样理解这个“动态”呢?

或者说一门语言具备了什么特性,才能称之为动态语言呢?

 

对于java,我是这样理解的。

我们都知道JVM(java虚拟机)执行的不是本地机器码指令,

而是执行一种称之为字节码的指令(存在于class文件中)。

这就要求虚拟机在真正执行字节码之前,先把相关的class文件加载到内存中。

虚拟机不是一次性加载所有需要的class文件,因为它在执行的时候根本不会知道以后会用到哪些class文件。

它是每用到一个类,就会在运行时“动态地”加载和这个类相关的class文件。

这就是java被称之为动态性语言的根本原因。

除了动态加载类之外,还会动态的初始化类,对类进行动态链接。

 

在JVM中负责对类进行加载的正是本文要介绍的类加载器(ClassLoader),所以,类加载器是JVM不可或缺的重要组件。

 

java中的类加载器及类加载器工作原理

 

java中(指的是javase)有三种类加载器。

每个类加载器在创建的时候已经指定他们对应的目录, 也就是说每个类加载器去哪里加载类是确定的,我认为在ClassLoader类中应该会有getTargetPath()之类的方法, 得到他们对应的路径,找了找jdk的文档,发现是没有的。

以下是这三种类加载器和他们对应的路径:

 

 * AppClassLoader  --   加载classpath指定的路径中的类

 * ExtClassLoader   --   加载jre/lib/ext目录下或者java.ext.dirs系统属性定义的目录下的类

 * BootStrap           --   加载JRE/lib/rt.jar中的类

 

那么类加载器是如何工作的呢?

可以参看jdk中ClassLoader类的源码。这个类的实现使用了模板方法模式,首先是loadClass方法来加载类,loadClass方法又调用了findClass方法,该方法读取并返回类文件的数据,findClass方法返回后,loadClass方法继续调用defineClass方法,将返回的数据加工成虚拟机运行时可识别的类型信息。

所以,我们如果开发自己的类加载器,只需要继承jdk中的ClassLoader类,并覆盖findClass方法就可以了,剩下的而工作,父类会完成。

  1. class MyClassLoader extends ClassLoader {  
  2.     @Override  
  3.     public Class<?> loadClass(String name) throws ClassNotFoundException {  
  4.         String fileName = name.substring(name.lastIndexOf(".") + 1) + ".class";  
  5.         InputStream in = getClass().getResourceAsStream(fileName);  
  6.         if (in == null) {  
  7.             return super.loadClass(name);  
  8.         }  
  9.         byte[] b = null;  
  10.         try {  
  11.             b = new byte[in.available()];  
  12.             in.read(b);  
  13.             in.close();  
  14.         } catch (IOException e) {  
  15.             e.printStackTrace();  
  16.         }  
  17.         return defineClass(name, b, 0, b.length);  
  18.     }  
  19. }  

其他java平台有的根据自己的需求,实现了自己特定的类加载器,

例如javaee平台中的tomcat服务器,Android平台中的dalvik虚拟机也定义了自己的类加载器。

 

虚拟机加载类有两种方式,一种方式就是上面提到的ClassLoader.loadClass()方法,

另一种是使用反射API,Class.forName()方法,其实Class.forName()方法内部也是使用的ClassLoader。

指定参数ClassLoader的话就用指定的;否则,返回的是调用者的类加载器。

Class类中forName方法的实现如下:

[java] 
 
  1. public static Class<?> forName(String name, boolean initialize,  
  2.                    ClassLoader loader)  
  3.         throws ClassNotFoundException  
  4.     {  
  5.     if (loader == null) {  
  6.         SecurityManager sm = System.getSecurityManager();  
  7.         if (sm != null) {  
  8.         ClassLoader ccl = ClassLoader.getCallerClassLoader();  
  9.         if (ccl != null) {  
  10.             sm.checkPermission(  
  11.             SecurityConstants.GET_CLASSLOADER_PERMISSION);  
  12.         }  
  13.         }  
  14.     }  
  15.     return forName0(name, initialize, loader);  
  16.     }  
  17.   
  18.     /** Called after security checks have been made. */  
  19.     private static native Class forName0(String name, boolean initialize,  
  20.                         ClassLoader loader)  
  21.     throws ClassNotFoundException;  

以上是关于深入理解java:1.1.类加载器的主要内容,如果未能解决你的问题,请参考以下文章

类加载器

深入理解java:1.1.类加载器

深入理解:java类加载器

深入理解Java类加载器:Java类加载原理解析

深入理解Java类加载器:线程上下文类加载器

深入理解Java虚拟机 类的加载器