类加载

 

类从被加载到虚拟机内存中开始,到卸载出内存为止,整个生命周期:

 




 

一、类加载的时机

 

1. 实例化对象的时候、读取或设置一个类的静态字段的时候、调用一个类的静态方法的时候;

 

2. 使用java.lang.reflect包的方法对类进行反射调用的时候;

 

3. 当初始化一个类,发现其父类还没有进行过初始化,则需要先触发其父类初始化;

 

4. 当虚拟机启动时,用户需要指定一个要执行的主类,虚拟机会先初始化这个主类;

 

5. 当使用jdk1.7的动态语言时,

 

接口的初始化与类的初始化的区别:当一个类在初始化时,其父类必须全部都已经初始化过了,但是接口不一样,它不一定要其父接口全部都完成初始化,只是在真正使用到父接口的时候才让其初始化。

 

二、类加载的过程

 

1.加载:将一个类的二进制字节流代表的静态存储结构转化为方法区的运行时数据结构,相应的在内存中生成class对象,作为方法区这个类的各自数据的访问入口。具体可能的加载文件:(1)从zip中读取,如jar\ear\war(2)从网络中读取,如applet;(3)运行时计算生成,如reflect;(4)从其他文件读取,如jsp

 

2.验证:校验class文件的字节流中包含的信息是否符合当前虚拟机的要求

 

3.准备:主要是为类变量分配内存,并设置其初始值(注意:内存在方法区进行分配,变量的实际值在编译后,才可与变量关联映射上)

 

4.解析:主要是虚拟机将常量池的符号引用替换为直接引用

 

5.初始化:具体真正开始执行类中定义的Java程序代码

 

三、类加载器

 

比较两个类是否“相等”,必须这两个类是由同一个类加载器加载才有意义,否则,即使这两个类来源于同一个Class文件,被同一个虚拟机不同的类加载器加载,这两个类也是不相等的。

 

双亲委派模型:是一个类加载器接收到类加载请求时,首先将请求委托给父类加载器去完成,保证所有的加载请求最终都是由启动类加载器加载。避免了用户自己定义已经加载的对象,通过其它加载器加载,使得java程序会变得一片混乱。

 



 

 

查看java.lang.ClassLoader的loadClass()方法,逻辑:

 

1.   先检查是否已经被加载过

 

2.   如果没有加载则调用父加载器的loadClass方法

 

3.   如果父加载器为空则默认使用启动类加载器加载

 

4.   如果加载失败,抛出ClassNotFoundException异常后,再调用自己的findClass方法进行加载

  protected Class<?> loadClass(String name, boolean resolve)
        throws ClassNotFoundException
    {
        synchronized (getClassLoadingLock(name)) {
            // First, check if the class has already been loaded
            Class<?> c = findLoadedClass(name);
            if (c == null) {
                long t0 = System.nanoTime();
                try {
                    if (parent != null) {
                        c = parent.loadClass(name, false);
                    } else {
                        c = findBootstrapClassOrNull(name);
                    }
                } catch (ClassNotFoundException e) {
                    // ClassNotFoundException thrown if class not found
                    // from the non-null parent class loader
                }

                if (c == null) {
                    // If still not found, then invoke findClass in order
                    // to find the class.
                    long t1 = System.nanoTime();
                    c = findClass(name);

                    // this is the defining class loader; record the stats
                    sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);
                    sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
                    sun.misc.PerfCounter.getFindClasses().increment();
                }
            }
            if (resolve) {
                resolveClass(c);
            }
            return c;
        }
    }

 
破坏双亲委派模型

 

第一次:引入双亲委派模型,在jdk1.2时

 

第二次:解决某些基础类要调用回用户的代码,比如JNDI服务

 

第三次:解决追求程序的动态性,比如代码热替换(HotSwap)、模块热部署(Hot Deploymnet),了解osgj的类加载器能掌握类加载的精髓

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值