lassLoader主要对类的请求提供服务,当JVM需要某类时,它根据名称向ClassLoader要求这个类,然后由ClassLoader返回这个类的class对象。

ClassLoader负责载入系统的所有资源(Class,文件,图片,来自网络的字节流等),通过ClassLoader从而将资源载入JVM 中。每个class都有一个引用,指向自己的ClassLoader。

1. 获得ClassLoader的几种方法

可以通过如下3种方法得到ClassLoader :

  1. this.getClass.getClassLoader();  // 使用当前类的ClassLoader
  2. Thread.currentThread().getContextClassLoader();  // 使用当前线程的ClassLoader
  3. ClassLoader.getSystemClassLoader();  // 使用系统ClassLoader,即系统的入口点所使用的ClassLoader。

注:system ClassLoader与根ClassLoader并不一样。JVM下system ClassLoader通常为App ClassLoader。

2. 用ClassLoader载入资源的几种方法

所有资源都通过ClassLoader载入到JVM里,那么在载入资源时当然可以使用ClassLoader,只是对于不同的资源还可以使用一些别的方式载入,例如对于类可以直接new,对于文件可以直接做IO等。

2.1 类的载入方式

假设有类A和类B,A在其方法里需要实例化B,载入类可能的方法有3种。对于载入类的情况,用户需要知道B类的完整名字(包括包名,例如"com.alexia.B")

1. 使用Class静态方法 Class.forName

  1. Class cls = Class.forName("com.alexia.B");
  2. B b = (B)cls.newInstance();

2. 使用ClassLoader

  1. /* Step 1. Get ClassLoader */
  2. ClassLoader cl = this.getClass.getClassLoader();;  // 如何获得ClassLoader参考1
  3. /* Step 2. Load the class */
  4. Class cls = cl.loadClass("com.alexia.B"); // 使用第一步得到的ClassLoader来载入B
  5. /* Step 3. new instance */
  6. B b = (B)cls.newInstance(); // 有B的类得到一个B的实例

3. 直接new

  1. B b = new B();

注:有人心里可能会想,对于类的载入方式我们都会选择最简单的第3种方式,前两种方式完全是多余。

实则不然,直接new的方式也是有局限的,举个最简单的例子:Java中有包名的类怎么引用默认包中的类?当然说这个是因为有包名的类不能直接用new引用默认包中的类,那么怎么办呢?答案是使用反射机制,即使用第一种方式来加载类(具体请看这里)。而且,用new()和用newInstance()创建类的实例是不同的,主要区别简单描述如下:

从JVM的角度看,我们使用关键字new创建一个类的时候,这个类可以没有被加载。但是使用newInstance()方法的时候,就必须保证:

(1)这个类已经加载;

(2)这个类已经链接了(即为静态域分配存储空间,并且如果必须的话将解析这个类创建的对其他类的所有引用)。而完成上面两个步骤的正是Class的静态方法forName()所完成的,这个静态方法调用了启动类加载器,即加载javaAPI的那个加载器。

可以看出,newInstance()实际上是把new这个方式分解为两步,即首先调用Class加载方法加载某个类,然后实例化。这样分步的好处是显而易见的。我们可以在调用class的静态加载方法forName时获得更好的灵活性,提供给了一种降耦的手段。

 

2.2 文件的载入方式(例如配置文件等)

假设在com.alexia.A类里想读取文件夹 /com/alexia/config 里的文件sys.properties,读取文件可以通过绝对路径或相对路径,绝对路径很简单,在Windows下以盘号开始,在Unix下以"/"开始。对于相对路径,其相对值是相对于ClassLoader的,因为ClassLoader是一棵树,所以这个相对路径和ClassLoader树上的任何一个ClassLoader相对比较后可以找到文件,那么文件就可以找到。文件有以下三种加载方式:

1. 直接用IO流读取

  1. /**
  2. * 假设当前位置是 "C:/test",通过执行如下命令来运行A "java com.aleixa.A"
  3. * 1. 在程序里可以使用绝对路径,Windows下的绝对路径以盘号开始,Unix下以"/"开始
  4. * 2. 也可以使用相对路径,相对路径前面没有"/"
  5. * 因为我们在 "C:/test" 目录下执行程序,程序入口点是"C:/test",相对路径就
  6. * 是 "com/alexia/config/sys.properties"
  7. * (例子中,当前程序的ClassLoader是App ClassLoader,system ClassLoader = 当前的
  8. * 程序的ClassLoader,入口点是"C:/test")
  9. * 对于ClassLoader树,如果文件在jdk lib下,或在jdk lib/ext下,或在环境变量里,
  10. * 都可以通过相对路径"sys.properties"找到,lib下的文件最先被找到
  11. */
  12. File f = new File("C:/test/com/aleixa/config/sys.properties"); // 使用绝对路径
  13. //File f = new File("com/alexia/config/sys.properties"); // 使用相对路径
  14. InputStream is = new FileInputStream(f);

2. 使用ClassLoader

  1. /**
  2. * 因为有3种方法得到ClassLoader,对应有如下3种ClassLoader方法读取文件
  3. * 使用的路径是相对于这个ClassLoader的那个点的相对路径,此处只能使用相对路径
  4. */
  5. InputStream is = null;
  6. is = this.getClass().getClassLoader().getResourceAsStream(
  7. "com/alexia/config/sys.properties"); //方法1
  8. //is = Thread.currentThread().getContextClassLoader().getResourceAsStream(
  9. "com/alexia/config/sys.properties"); //方法2
  10. //is = ClassLoader.getSystemResourceAsStream("com/alexia/config/sys.properties"); //方法3

3. 使用ResourceBundle

  1. ResourceBundle bundle = ResourceBundle.getBoundle("com.alexia.config.sys");

这种用法通常用来载入用户的配置文件,关于ResourceBunlde更详细的用法请参考其他文档。

注:如果是属性配置文件,也可以通过java.util.Properties.load(is)将内容读到Properties里,Properties默认认为is的编码是ISO-8859-1,如果配置文件是非英文的,可能出现乱码问题。

总结:有如下3种途径来载入文件

1. 绝对路径 ---> IO
    2. 相对路径 ---> IO 
                      ---> ClassLoader 
    3. 资源捆绑 ---> ResourceBundle

2.3 web资源的载入方式

在web应用里当然也可以使用ClassLoader来载入资源,但更常用的情况是使用ServletContext,如下是web目录结构 
    ContextRoot 
       |- JSP、HTML、Image等各种文件 
        |- [WEB-INF] 
              |- web.xml 
              |- [lib] Web用到的JAR文件 
                |- [classes] 类文件

用户程序通常在classes目录下,如果想读取classes目录里的文件,可以使用ClassLoader,如果想读取其他的文件,一般使用ServletContext.getResource()。

如果使用ServletContext.getResource(path)方法,路径必须以"/"开始,路径被解释成相对于ContextRoot的路径,此处载入文件的方法和ClassLoader不同,举例"/WEB-INF/web.xml","/download/WebExAgent.rar"

Java中用ClassLoader载入各种资源(类、文件、web资源)的方法的更多相关文章

  1. Struts2 之 Action 类访问 WEB 资源

    接着上次博客的内容我继续分享我所学到的知识,和自己在学习过程中所遇到问题以及解决方案.当然,如果读者发现任何问题均可以在下方评论告知我,先谢! 在 Action 中访问 WEB 资源 web 资源 所 ...

  2. ClassLoader载入指定的类需注意六个细节或报ClassNotFundEception异常总结

    项目中,载入指定的类反射调用方法一直报类找不到,经过数百次的測试.对这样的问题有了一个又一次的认识,特总结.记录.分享例如以下: 1.路径中尽可能用"/"或者File.separa ...

  3. PHP __autoload函数(自动载入类文件)的使用方法(转)

    详细出处参考:http://www.jb51.net/article/29625.htm 在使用PHP的OO模式开发系统时,通常大家习惯上将每个类的实现都存放在一个单独的文件里,这样会很容易实现对类进 ...

  4. Core Java 总结(字符和字符串类问题)

    所有代码均在本地编译运行测试,环境为 Windows7 32位机器 + eclipse Mars.2 Release (4.5.2) 2016-10-17 整理 字符,字符串类问题 正则表达式问题 J ...

  5. [Java类加载器]Java中classLoader浅析.

    本文为在公司内部TD上写的一篇小文, 主要讲解java中classLoader基础知识, 现在拿来这里分享一下. 一.问题 请在Eclipse中新建如下类,并运行它: 1 package java.l ...

  6. 【Android 应用开发】Android资源文件 - 使用资源存储字符串 颜色 尺寸 整型 布尔值 数组

    . 作者 : 万境绝尘 转载请注明出处 : http://blog.csdn.net/shulianghan/article/details/19913755 . 一. Android资源文件简介 1 ...

  7. Java中必须了解的常用类

    1.Java的包装类 基本数据类型我们都很熟悉,例如:int.float.double.boolean.char等,基本数据类型不具备对象的特征,不能调用方法,一般能实现的功能比较简单,为了让基本数据 ...

  8. Python Cookbook(第3版)中文版:15.19 从C语言中读取类文件对象

    15.19 从C语言中读取类文件对象¶ 问题¶ 你要写C扩展来读取来自任何Python类文件对象中的数据(比如普通文件.StringIO对象等). 解决方案¶ 要读取一个类文件对象的数据,你需要重复调 ...

  9. J2EE之普通类载入web资源文件的方法

    在WEB中普通类并不能像Servlet那样通过this.getServletContext().getResourceAsStream()获取web资源,须要通过类载入器载入,这里有两种方式,这两种方 ...

随机推荐

  1. CODE[VS]4633Mz树链剖分练习

    Description 给定一棵结点数为n的树,初始点权均为0,有依次q个操作,每次操作有三个参数a,b,c,当a=1时,表示给b号结点到c号结点路径上的所有点(包括b,c,下同)权值都增加1,当a= ...

  2. 视区相关单位vw, vh..简介以及可实际应用场景

    这篇文章发布于 2012年09月24日,星期一,01:15,归类于 css相关. 阅读 37012 次, 今日 12 次 by zhangxinxu from http://www.zhangxinx ...

  3. nignx 启动,重启命令

    1.查看进程号  ps -ef|grep nginx 强制停止 [root@LinuxServer ~]# pkill -9 nginx 重启 1.验证nginx配置文件是否正确 方法一:进入ngin ...

  4. ie8兼容性(不支持trim 、readonly光标、乱码encodeURI())

    IE8下String的Trim()方法失效的解决方案 1.用jquery的trim()方法,$.trim(str)就可以了. 2.String扩展: 第一种 String.prototype.trim ...

  5. Chrome开发者工具不完全指南(六、插件篇)

    本篇是Chrome开发者工具的结尾篇,最后为大家介绍几款功能强大的插件.在chrome商店里面有很多插件,没事建议大家去逛逛.不过需要FQ,所以诸位请自备神器.一.皮肤插件 首先是大家期盼已久,翘首以 ...

  6. Zookeeper 3.4.6 Client端流程粗略梳理

    首先从Zookeeper入手,Zookeeper-->ClientCnxn-->sendThread/eventThread public ZooKeeper(String connect ...

  7. 利用__index和__newindex实现默认值表、监控表、只读表

    __index和__newindex实际上相当于是在读写表的时候分别加了一道过滤的逻辑,让读写表的操作可以被监控或说回调,利用这个特性可以实现一些带有特殊功能的表. 带有默认值的表: setdefau ...

  8. Android适配器之ArrayAdapter、SimpleAdapter和BaseAdapter的简单用法与有用代码片段(转)

    摘自:http://blog.csdn.net/shakespeare001/article/details/7926783 Adapter是连接后端数据和前端显示的适配器接口,是数据Data和UI( ...

  9. jackson annotations注解详解 (zhuan)

    http://blog.csdn.net/sdyy321/article/details/40298081 ************************************** 官方WIKI: ...

  10. 特征值提取之 -- TF-IDF值的简单介绍

    首先引用百度百科的话: "TF-IDF是一种统计方法,用以评估一字词对于一个文件集或一个语料库中的其中一份文件的重要程度.字词的重要性随着它在文件中出现的次数成正比增加,但同时会随着它在语料 ...