103.【JAVA编程】类加载机制

不错的文章:http://blog.csdn.net/wangyy130/article/details/48828595

 

类的加载机制

每创建一个Java类时,都会生产一个.class文件,内存中对应生成一个class对象;

来表示该类的类型信息;我们可以用.class来获取这个类的所有信息;

也可以通过getClass()方法来读取这个类的所有信息;

比如getClass().getInterfaces()获取类的接口信息等。

在Java类加载时,要通过一个类加载器classloader来将生成的Java类加载到JVM中才能执行。

 

Proxy.newProxyInstance方法中,共有三个参数:

1、targetObject.getClass().getClassLoader()目标对象通过getClass方法获取类的所有信息后,

调用getClassLoader() 方法来获取类加载器。获取类加载器后,可以通过这个类型的加载器,

在程序运行时,将生成的代理类加载到JVM即Java虚拟机中,以便运行时需要!

2、targetObject.getClass().getInterfaces()获取被代理类的所有接口信息,

以便于生成的代理类可以具有代理类接口中的所有方法。

3、this:我们使用动态代理是为了更好的扩展,比如在方法之前做什么,之后做什么等操作。

这个时候这些公共的操作可以统一交给代理类去做。

这个时候需要调用实现了InvocationHandler 类的一个回调方法。由于自身变实现了这个方法,所以将this传递过去。

ClassLoader

1、类加载过程

「加载」将类的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在内存上创建一个java.lang.Class对象用来封装类在元数据区的数据结构作为这个类的各种数据的访问入口。

「验证」主要是为了确保class文件中的字节流包含的信息是否符合当前JVM的要求,且不会危害JVM自身安全,比如校验文件格式、是否是cafe baby魔术、字节码验证等等。

「准备」为类变量分配内存并设置类变量(是被static修饰的变量,变量不是常量,所以不是final的,就是static的)初始值的阶段。这些变量所使用的内存在方法区中进行分配。比如private static int age = 26;类变量age会在准备阶段过后为 其分配四个(int四个字节)字节的空间,并且设置初始值为0,而不是26。若是final的,则在编译期就会设置上最终值。

「解析」JVM会在此阶段把类的二进制数据中的符号引用替换为直接引用。

「初始化」初始化阶段是执行类构造器<clinit>()方法的过程,到了初始化阶段,才真正开始执行类定义的Java程序代码(或者说字节码 )。比如准备阶段的那个age初始值是0,到这一步就设置为26。

「使用」对象都出来了,业务系统直接调用阶段。

「卸载」用完了,可以被GC回收了。

2、类加载器种类以及加载范围

「启动类加载器(Bootstrap ClassLoader)」最顶层类加载器,他的父类加载器是个null,也就是没有父类加载器。负责加载jvm的核心类库,比如java.lang.*等,从系统属性中的sun.boot.class.path所指定的目录中加载类库。他的具体实现由Java虚拟机底层C++代码实现。

「扩展类加载器(Extension ClassLoader)」父类加载器是Bootstrap ClassLoader。从java.ext.dirs系统属性所指定的目录中加载类库,或者从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库,如果把用户的jar文件放在这个目录下,也会自动由扩展类加载器加载。继承自java.lang.ClassLoader

「应用程序类加载器(Application ClassLoader)」父类加载器是Extension ClassLoader。从环境变量classpath或者系统属性java.class.path所指定的目录中加载类。继承自java.lang.ClassLoader

「自定义类加载器(User ClassLoader)」除了上面三个自带的以外,用户还能制定自己的类加载器,但是所有自定义的类加载器都应该继承自java.lang.ClassLoader。比如热部署、tomcat都会用到自定义类加载器。

3、双亲委派是什么

如果一个类加载器收到了类加载的请求,他首先会从自己缓存里查找是否之前加载过这个class,加载过直接返回,没加载过的话他不会自己亲自去加载,他会把这个请求委派给父类加载器去完成,每一层都是如此,类似递归,一直递归到顶层父类。也就是Bootstrap ClassLoader,只要加载完成就会返回结果,如果顶层父类加载器无法加载此class,则会返回去交给子类加载器去尝试加载,若最底层的子类加载器也没找到,则会抛出ClassNotFoundException

源码在java.lang.ClassLoader#loadClass(java.lang.String, boolean)

双亲委派的目的:防止内存中出多份同的字节码,安全。

6、如何破坏双亲委派模型

重写loadClass方法,别重写findClass方法,因为loadClass是核心入口,将其重写成自定义逻辑即可破坏双亲委派模型。

7、如何自定义一个类加载器

只需要继承java.lang.Classloader类,然后覆盖他的findClass(String name)方法即可,该方法根据参数指定的类名称,返回对应 的Class对象的引用。

8、热部署原理

采取破坏双亲委派模型的手段来实现热部署,默认的loadClass()方法先找缓存,你改了class字节码也不会热加载,所以自定义ClassLoader,去掉找缓存那部分,直接就去加载,也就是每次都重新加载。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值