java获取类的classloader,对ClassLoader的一些简单总结

参考:http://blog.csdn.net/briblue/article/details/54973413,http://blog.csdn.net/qbg19881206/article/details/8890600,http://zyjustin9.iteye.com/blog/2022654,https://www.cnblogs.com/tuning/p/6943427.html

一、ClassLoader的作用?

ClassLoader翻译过来就是类加载器。jvm启动的时候,并不会一次性加载所有的class文件,而是根据需要去动态地加载。ClassLoader的作用就是将class文件加载到jvm虚拟机中去。

二、java自带的三个类加载器

1。Bootstrap ClassLoader。最顶层的加载类,主要加载核心类库,加载%JRE_HOME%\lib下的rt.jar、resources.jar、charsets.jar和class等。

2。Extention ClassLoader。扩展的类加载器,负责加载目录%JRE_HOME%\lib\ext目录下的jar包和class文件。

3。Appclass Loader,也称为SystemAppClass,加载当前应用的classpath的所有类。

4。我们可以自己写类加载器,加载类和资源。

三、类加载器间的关系

AppClassLoader的父加载器是ExtClassLoader,ExtClassLoader的父加载器是Bootstrap ClassLoader。

如果一个ClassLoader创建时如果没有指定parent,那么它的parent默认就是AppClassLoader。

四、类加载器的加载顺序

类加载器之间采用双亲委托的方式进行加载class。

一个类加载器查找class和resource时,是通过“委托模式”进行的。它首先判断这个class是不是已经加载,如果没有的话就交给父加载器进行查找是否已加载,父加载器如果也没有加载过,就交给更上层的类加载器查找,直至找到已加载这个class的类加载器,返回这个类,或者直到Bootstrap ClassLoader,如果Bootstrap classloader已加载,则直接返回,如果没加载就进行查找。如果没有找到,就交给下级加载器去查找加载,如果下级加载器没有加载到,就交给下级去加载,加载到即返回,直至最下层的加载器。

五、线程的contextClassLoader

1)contextClassLoader只是Thread类一个成员变量,通过setContextClassLoader()方法设置,通过getContextClassLoader()获取。

每个Thread都有一个相关联的ClassLoader,默认是AppClassLoader。并且子线程默认使用父线程的ClassLoader,除非子线程特别设置。

2)this.getClass.getClassLoader()和Thread.currentThread().getContextClassLoader()的区别

方法一得到的Classloader是静态的,表明类的载入者是谁;方法二得到的Classloader是动态的,谁执行(某个线程),就是那个执行者的Classloader,所以子线程默认使用父线程的ClassLoader。对于单例模式的类,静态类等,载入一次后,这个实例会被很多程序(线程)调用,对于这些类,载入的Classloader和执行线程的Classloader通常都不同。

六、获得ClassLoader的3种方法

this.getClass().getClassLoader(); // 使用当前类的ClassLoader。

Thread.currentThread().getContextClassLoader(); // 使用当前线程的ClassLoader。

ClassLoader.getSystemClassLoader(); // 使用系统ClassLoader,JVM下system ClassLoader通常为App ClassLoader。

七、class.getName()等方法

当你使用class.forName(),class.getName(),class.getResource()这几个不带ClassLoader参数的方法时,默认使用当前类的ClassLoader。

八、类加载器的getResource()方法

1.this.getClass().getResource("");//得到当前类class文件的URI目录。

2.this.getClass().getResource("/");//得到当前的classpath的绝对URI路径。

3.this.getClass().getClassLoader().getResource("");//得到当前ClassPath的绝对URI路径。

4.ClassLoader.getSystemResource("");//得到的当前ClassPath的绝对URI路径。

5.Thread.currentThread().getContextClassLoader().getResource("");得到当前ClassPath的绝对URI路径。

Class.getResourse()和Class.getClassLoader().getResource()

这两个getResource()是使用当前ClassLoader加载资源(即资源在classpath中),这样资源和class直接打在jar包中,避免文件路径问题。两者不同是Class的getResource()方法是从当前class文件路径查找资源,ClassLoader则是从jar包根目录查找。

九、用Classloader载入资源

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

1)实例化类B的三种方案

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

Class cls = Class.forName("com.rain.B");

B b = (B)cls.newInstance();

2. 使用ClassLoader

ClassLoader cl;//可以用前面提到的几种方法

Class cls = cl.loadClass("com.rain.B"); // 使用第一步得到的ClassLoader来载入B

B b = (B)cls.newInstance(); // 有B的类得到一个B的实例

3. 直接new

B b = new B();

2)文件载入(例如配置文件等)假设在com.rain.A类里想读取文件夹 /com/rain/config 里的文件sys.properties,读取文件可以通过绝对路径或相对路径,绝对路径很简单,在Windows下以盘号开始,在Unix下以"/"开始。对于相对路径,其相对值是相对于ClassLoader的,因为ClassLoader是一棵树,所以这个相对路径和ClassLoader树上的任何一个ClassLoader相对比较后可以找到文件,那么文件就可以找到。

1. 直接IO

File f = new File("C:/test/com/rain/config/sys.properties"); // 使用绝对路径

//File f = new File("com/rain/config/sys.properties"); // 使用相对路径

InputStream is = new FileInputStream(f);

2. 使用ClassLoader

因为有3种方法得到ClassLoader,对应有如下3种方法读取文件。 使用的路径是相对于这个ClassLoader的那个点的相对路径,此处只能使用相对路径

InputStream is = null;

is = this.getClass().getClassLoader().getResourceAsStream("com/rain/config/sys.properties"); //方法1

//is = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/rain/config/sys.properties"); //方法2

//is = ClassLoader.getSystemResourceAsStream("com/rain/config/sys.properties"); //方法3

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值