ImageVerifierCode 换一换
格式:DOCX , 页数:18 ,大小:54.73KB ,
资源ID:2947797      下载积分:20 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.docduoduo.com/d-2947797.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录   微博登录 

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(深入理解Java中的类加载器.docx)为本站会员(dreamzhangning)主动上传,道客多多仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知道客多多(发送邮件至docduoduo@163.com或直接QQ联系客服),我们立即给予删除!

深入理解Java中的类加载器.docx

1、首先声明,我是因为看了 ImportNew 网站上的几篇关于类加载器的文章之后,才萌生了写这篇文章的想法。所以在写这篇文章时,参考了该网站上的几篇相关的文章,但是加入了很多自己的理解,绝对不是抄袭。从 java 的动态性到类加载机制我们知道,Java 是一种动态语言。那么怎样理解这个 “动态”呢?或者说一门语言具备了什么特性,才能称之为动态语言呢?对于 java,我是这样理解的。我们都知道 JVM( java 虚拟机)执行的不是本地机器码指令,而是执行一种称之为字节码的指令(存在于 class 文件中)。这就要求虚拟机在真正执行字节码之前,先把相关的 class 文件加载到内存中。虚拟机不是一

2、次性加载所有需要的 class 文件,因为它在执行的时候根本不会知道以后会用到哪些 class 文件。它是每用到一个类,就会在运行时“动态地”加载和这个类相关的 class 文件。这就是 java 被称之为动态性语言的根本原因。除了动态加载类之外,还会动态的初始化类,对类进行动态链接。动态初始化和动态链接放在其他文章中进行介绍。本文中只关心类的加载。在 JVM 中负责对类进行加载的正是本文要介绍的类加载器(ClassLoader),所以,类加载器是 JVM 不可或缺的重要组件。java 中的类加载器及类加载器工作原理java 中(指的是 javase)有三种类加载器。每个类加载器在创建的时候已

3、经指定他们对应的目录,也就是说每个类加载器去哪里加载类是确定的,我认为在 ClassLoader 类中应该会有 getTargetPath 之类的方法,得到他们对应的路径,找了找 jdk 的文档,发现是没有的。以下是这三种类加载器和他们对应的路径:* AppClassLoader -加载 classpath 指定的路径中的类* ExtClassLoader -加载 jre/lib/ext 目录下或者 java.ext.dirs 系统属性定义的目录下的类* BootStrap -加载 JRE/lib/rt.jar 中的类那么类加载器是如何工作的呢?可以参看 jdk 中 ClassLoader 类

4、的源码。这个类的实现使用了模板方法模式,首先是 loadClass 方法来加载类,loadClass 方法又调用了 findClass 方法,该方法读取并返回类文件的数据,findClass 方法返回后,loadClass 方法继续调用defineClass 方法,将返回的数据加工成虚拟机运行时可识别的类型信息。所以,我们如果开发自己的类加载器,只需要继承 jdk 中的 ClassLoader类,并覆盖 findClass 方法就可以了,剩下的而工作,父类会完成。其他java 平台有的根据自己的需求,实现了自己特定的类加载器,例如javaee 平台中的 tomcat 服务器, Android

5、平台中的 dalvik 虚拟机也定义了自己的类加载器。虚拟机加载类有两种方式,一种方式就是上面提到的ClassLoader.loadClass 方法,另一种是使用反射 API,Class.forName方法,其实 Class.forName 方法内部也是使用的 ClassLoader。Class类中 forName 方法的实现如下:java view plain copy1. public static Class forName(String name, boolean initialize,2. ClassLoader loader)3. throws ClassNotFoundExcep

6、tion4. 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, loade

7、r);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;类加载器的三个特性类加载器有三个特性,分别为委派,可见性和单一性,其他文章上对这三个特性的介绍如下:*委托机制是指将加载一个类的请求交给父类加载器,如果这个父类加载器不能够找到或者加载这个类,那么再加载它。*可见

8、性的原理是子类的加载器可以看见所有的父类加载器加载的类,而父类加载器看不到子类加载器加载的类。*单一性原理是指仅加载一个类一次,这是由委托机制确保子类加载器不会再次加载父类加载器加载过的类。其中,委派机制是基础,在其他资料中也把这种机制叫做类加载器的双亲委派模型,其实说的是同一个意思。可加性和单一性是依赖于委派机制的。以下代码测试类加载器的委派机制:java view plain copy1. ClassLoader appClassLoader = ClassLoaderTest.class.getClassLoader;2. System.out.println(appClassLoade

9、r); /sun.misc.Launcher$AppClassLoader19821f3.4.5. ClassLoader extClassLoader = appClassLoader.getParent;6. System.out.println(extClassLoader); /sun.misc.Launcher$ExtClassLoaderaddbf17. /AppClassLoader 的父加载器是 ExtClassLoader8.9. System.out.println(extClassLoader.getParent); /null10. /ExtClassLoader 的父

10、加载器是 null,也就是 BootStrap,这是由 c语言实现的由打印结果可知,加载我们自己编写的类的加载器是AppClassLoader,AppClassLoader 的父加载器是 ExtClassLoader,在而 ExtClassLoader 的父加载器返回结果为 null,这说明他的附加载器是 BootStrap,这个加载器是和虚拟机紧密联系在一起的,在虚拟机启动时,就会加载 jdk 中的类。它是由 C 实现的,没有对应的 java 对象,所以返回 null。但是在逻辑上,BootStrap 仍是 ExtClassLoader 的父加载器。也就是说每当 ExtClassLoader

11、 加载一个类时,总会委托给BootStrap 加载。系统类加载器和线程上下文类加载器在 java 中,还存在两个概念,分别是系统类加载器和线程上下文类加载器。其实系统类加载器就是 AppClassLoader 应用程序类加载器,它两个值得是同一个加载器,以下代码可以验证:java view plain copy1. ClassLoader appClassLoader = ClassLoaderTest.class.getClassLoader;2. System.out.println(appClassLoader); /sun.misc.Launcher$AppClassLoader198

12、21f3.4. ClassLoader sysClassLoader = ClassLoader.getSystemClassLoader;5. System.out.println(sysClassLoader); /sun.misc.Launcher$AppClassLoader19821f6. /由上面的验证可知,应用程序类加载器和系统类加载器是相同的,因为地址是一样的这两个类加载器对应的输出,不仅类名相同,连对象的哈希值都是一样的,这充分说明系统类加载器和应用程序类加载器不仅是同一个类,更是同一个类的同一个对象。每个线程都会有一个上下文类加载器,由于在线程执行时加载用到的类,默认情况下

13、是父线程的上下文类加载器,也就是 AppClassLoader。java view plain copy1. new Thread(new Runnable 2.3. Override4. public void run 5. ClassLoader threadcontextClassLosder = Thread.currentThread.getContextClassLoader;6. System.out.println(threadcontextClassLosder); /sun.misc.Launcher$AppClassLoader19821f7. 8. ).start;这个

14、子线程在执行时打印的信息为sun.misc.Launcher$AppClassLoader19821f,可以看到和主线程中的 AppClassLoader 是同一个对象(哈希值相同)。也可以为线程设置特定的类加载器,这样的话,线程在执行时就会使用这个特定的类加载器来加载使用到的类。如下代码:java view plain copy1. Thread th = new Thread(new Runnable 2.3. Override4. public void run 5. ClassLoader threadcontextClassLosder = Thread.currentThread.

15、getContextClassLoader;6. System.out.println(threadcontextClassLosder); /jg.zhang.java.testclassloader.ClassLoaderTest$31b67f747. 8. );9.10. th.setContextClassLoader(new ClassLoader );11.12. th.start;在线程运行之前,为它设置了一个匿名内部类的类加载器对象,线程运行时,输出的信息为:jg.zhang.java.testclassloader.ClassLoaderTest$31b67f74,也就是我们

16、设置的那个类加载器对象。类加载器的可见性下面验证类加载器的可见性,也就是子类的加载器可以看见所有的父类加载器加载的类,而父类加载器看不到子类加载器加载的类。以下代码使用父加载器 ExtClassLoader 加载子加载器AppClassLoader 路径下的类,由输出可知,是不可能实现的。java view plain copy1. try 2. Class.forName(“jg.zhang.java.testConcurrent.Person“, true,3. ClassLoaderTest.class.getClassLoader.getParent);4. System.out.pr

17、intln(“1 -类被加载“);5. catch (ClassNotFoundException e) 6. /e.printStackTrace;7. System.out.println(“1 -未找到类“);8. 输出为 :1 -未找到类 。说明抛出了 ClassNotFoundException异常。原因是让 ExtClassLoader 加载 jg.zhang.java.testConcurrent.Person 这个类因为这个类不在jre/lib/ext 目录下或者 java.ext.dirs 系统属性定义的目录下,所以抛出ClassNotFoundException。所以父加载

18、器不能加载应该被子加载器加载的类。也就是说这个类在父加载器中不可见。这种机制依赖于委派机制。下面代码使用子加载器 AppClassLoader 加载父加载器 BootStrap中的类,这是可以实现的。java view plain copy1. try 2. Class.forName(“java.lang.String“, true,3. ClassLoaderTest.class.getClassLoader);4. System.out.println(“2 -类被加载“);5. catch (ClassNotFoundException e) 6. /e.printStackTrace

19、;7. System.out.println(“2 -未找到类“);8. 输出为:2 -类被加载。说明成功加载了 String 类。是因为在指定由 AppClassLoader 加载 String 类时,由 AppClassLoader 一直委派到BootStrap 加载。虽然是由子加载器的父加载器加载的,但是也可以说,父加载器加载的类对于子加载器来说是可见的。这同样依赖于委派机制。其实在虚拟机启动初期,java.lang.String 已经被 BootStrap 预加载了,这时再次加载,虚拟机发现已经加载,不会再重复加载。这同时也证明了类加载器的单一性。测试代码到此为止,类加载器的知识就全部

20、讲完了。以下是整个测试代码:java view plain copy1. package jg.zhang.java.testclassloader;2.3.4. /*5. *参考 ImportNew 上的一篇文章,6. *文章地址:http:/ *8. * Java 类加载器基于三个机制:委托、可见性和单一性。9. *委托机制是指将加载一个类的请求交给父类加载器,如果这个父类加载器不能够找到或者加载这个类,那么再加载它。10. *可见性的原理是子类的加载器可以看见所有的父类加载器加载的类,而父类加载器看不到子类加载器加载的类。11. *单一性原理是指仅加载一个类一次,这是由委托机制确保子类加

21、载器不会再次加载父类加载器加载过的类。12. *13. *三种类加载器:每个类加载器在创建的时候已经指定他们对应的目录, 也就是说每个类加载器去哪里加载类是确定的14. *我认为在 ClassLoader 类中应该会有 getTargetPath 之类的方法,得到他们对应的路径,找了找 jdk 的文档,发现是没有的.15. * AppClassLoader -加载 classpath 指定的路径中的类16. * ExtClassLoader -加载 jre/lib/ext 目录下或者 java.ext.dirs 系统属性定义的目录下的类17. * BootStrap -加载 JRE/lib/r

22、t.jar 中的类18. *19. *20. *21. * author zhangjg22. *23. */24. public class ClassLoaderTest 25.26.27. public static void main(String args) 28. test1;29. test2;30. test3;31. 32.33. /*34. *验证线程上下文类加载器35. */36. private static void test3 37. /*38. * 1 每个线程都会有一个上下文类加载器,由于在线程执行时加载用到的类,默认情况下是父线程39. *的上下文类加载器,也

23、就是 AppClassLoader40. */41. new Thread(new Runnable 42.43. Override44. public void run 45. ClassLoader threadcontextClassLosder = Thread.currentThread.getContextClassLoader;46. System.out.println(threadcontextClassLosder); /sun.misc.Launcher$AppClassLoader19821f47. 48. ).start;49.50. /*51. * 2 也可以给创建

24、的线程设定特定的上下文类加载器52. */53. Thread th = new Thread(new Runnable 54.55. Override56. public void run 57. ClassLoader threadcontextClassLosder = Thread.currentThread.getContextClassLoader;58. System.out.println(threadcontextClassLosder); /jg.zhang.java.testclassloader.ClassLoaderTest$31b67f7459. 60. );61.

25、62. th.setContextClassLoader(new ClassLoader );63.64. th.start;65. 66.67. /*68. *测试可见性,可见性依赖于委托机制69. */70. private static void test2 71.72. /*73. * 1 让 ExtClassLoader 加载 jg.zhang.java.testConcurrent.Person 这个类74. *因为这个类不在 jre/lib/ext 目录下或者 java.ext.dirs 系统属性定义的目录下75. *所以抛出 ClassNotFoundException76.

26、*77. *所以父加载器不能加载应该被子加载器加载的类 ,这个类在父加载器中不可见78. *这种机制依赖于委派机制79. */80.81. try 82. Class.forName(“jg.zhang.java.testConcurrent.Person“, true,83. ClassLoaderTest.class.getClassLoader.getParent);84. System.out.println(“1 -类被加载“);85. catch (ClassNotFoundException e) 86. /e.printStackTrace;87. System.out.pri

27、ntln(“1 -未找到类“);88. 89.90.91. /*92. * 2 让 AppClassLoader 加载 java.lang.String 类93. *没有抛出异常,说明类被正常加载了94. *虽然是由 AppClassLoader 一直委派到 BootStrap 而加载的95. *所以可以说,父加载器加载的类对于子加载器来说是可见的 ,这同样依赖于委派机制96. *97. *其实在虚拟机启动初期,java.lang.String 已经被 BootStrap 预加载了98. *这时再次加载,虚拟机发现已经加载 ,不会再重复加载99. */100. try 101. Class.f

28、orName(“java.lang.String“, true,102. ClassLoaderTest.class.getClassLoader);103. System.out.println(“2 -类被加载“);104. catch (ClassNotFoundException e) 105. /e.printStackTrace;106. System.out.println(“2 -未找到类“);107. 108.109. 110.111. /*112. *验证三种类加载器的父子关系113. */114. private static void test1 115. ClassL

29、oader appClassLoader = ClassLoaderTest.class.getClassLoader;116. System.out.println(appClassLoader); /sun.misc.Launcher$AppClassLoader19821f117.118. ClassLoader sysClassLoader = ClassLoader.getSystemClassLoader;119. System.out.println(sysClassLoader); /sun.misc.Launcher$AppClassLoader19821f120. /由上面

30、的验证可知,应用程序类加载器和系统类加载器是相同的,因为地址是一样的121.122. ClassLoader extClassLoader = appClassLoader.getParent;123. System.out.println(extClassLoader); /sun.misc.Launcher$ExtClassLoaderaddbf1124. /AppClassLoader 的父加载器是 ExtClassLoader125.126. System.out.println(extClassLoader.getParent); /null127. /ExtClassLoader 的父加载器是 null,也就是 BootStrap,这是由 c语言实现的128.129. 130.131.

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报