从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方法的实现如下:

  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. /** Called after security checks have been made. */
  18. private static native Class forName0(String name, boolean initialize,
  19. ClassLoader loader)
  20. throws ClassNotFoundException;

最新文章

  1. 《Node web开发》笔记
  2. java class的property的get和set方法生成规则
  3. 系列文章:老项目的#iPhone6与iPhone6Plus适配#(持续更新中,更新日期2014年10月12日 星期日 )
  4. Java甘特图控件swing版免费下载地址
  5. StringUtilsd的isEmpty、isNotEmpty、isBlank、isNotBlank
  6. Web前端开发:什么是页面重回(repaints)与回流(reflow)
  7. Redis基础知识之—— 缓存应用场景
  8. mysql 聚集函数和分组
  9. IAAS云计算产品畅想-公有云主机产品优势
  10. oracle中简单查询语句的格式及执行顺序分析
  11. BASE2(matlab)
  12. TypeScript教程2
  13. 2.3 InnoDB 体系架构
  14. Sql Server 获取存储过程或函数创建语句
  15. java多线程读一个变量需要加锁吗?
  16. log4j2配置文件log4j2.xml详解(转载)
  17. Oracle EBS 新增 OAFM 个数
  18. 获取和设置URL里星号(#)的参数
  19. 正则表达式(Java版整理)
  20. [转载]理解Tomcat的Classpath-常见问题以及如何解决

热门文章

  1. python paramiko模块:远程连接服务器
  2. 【JSOI2014】歌剧表演
  3. [洛谷P3320] SDOI2015 寻宝游戏
  4. web开发常见的几大安全问题
  5. C# 、Java数组申明、初始化区别
  6. Winserver-禁止程序启动
  7. 参数上使用自定义注解在aop中无法获取到该参数
  8. 结合webpack实现children子路由,抽离路由模块
  9. [CF1093G]Multidimensional Queries:线段树
  10. Module——模块加载语法