zoukankan      html  css  js  c++  java
  • jvm(2)---类加载机制

    1.类加载:类加载器将class文件加载到虚拟机的内存
    加载:在硬盘上查找并通过IO读入字节码文件
    连接:执行校验、准备、解析步骤
    校验:校验字节码文件的正确性
    准备:给类的静态变量分配内存,并赋予默认值
    解析:类装载器装入类所引用的其他所有类
    初始化:对类的静态变量初始化为指定的值,执行静态代码块

    2.类加载器

    启动类加载器(BootstrapClassLoader):负责加载JRE的核心类库,如jre目标下的rt.jar,charsets.jar等
    扩展类加载器(ExtensionClassLoader):负责加载JRE扩展目录ext中JAR类包
    系统类加载器(ApplicationClassLoader):负责加载ClassPath路径下的类包
    用户自定义加载器(CustomClassLoader):负责加载用户自定义路径下的类包

    执行如下代码,查看对应的类加载器:

    package com.nijunyang.spring;
    
    
    import com.sun.crypto.provider.BlowfishCipher;
    
    /**
     * @author: create by nijunyang
     * @date:2019/6/16
     */
    public class ClassLoaderTest {
        public static void main(String[] args)
        {
            System.out.println(String.class.getClassLoader());
            System.out.println(BlowfishCipher.class.getClassLoader().getClass().getName());
            System.out.println(ClassLoaderTest.class.getClassLoader().getClass().getName());
            System.out.println(ClassLoader.getSystemClassLoader().getClass().getName());
        }
    }
    

     

     可以看到String的类加载器null,因为String是在java核心包rt.jar里面这里面东西是由启动类加载器加载的,而启动类加载器是由C/C++实现的,根本不在JDK里面

    BlowfishCipher的类加载器是ExtClassLoader,而这个类正是Jre扩展目录ext中jar包所在的类

    3.类加载机制--全盘委托和双亲委派机制

    全盘委托:当一个ClassLoader加载一个类时,除非显示的使用另一个ClassLoader,该类所依赖和引用的类也由这个ClassLoader载入,比如说A依赖B,那么B的加载器和A的加载器一样。

    双亲委派:指先委托父类加载器寻找目标类,在找不到的情况下在自己的路径中查找并载入目标类,感觉说父类加载器不是很合适,因为没有这一层关系,感觉更像是上下级关系。委托上级加载器寻找目标类。

    双亲委派的好处:

    1.避免类重复加载,上级加载了,下级就不需要再加载

    2.因为核心API都有固定的加载器,可以防止核心库被篡改: 自定义一个String类,同样在java.lang包下,运行代码会发现启动报错,实际加载的java.lang.String类并没有main方法,说明实际加载的String类并不是我们自定义的String类,而是因为双亲委派机制,往上委托到启动类加载器,去加载rt.jar里面的String类

    4.类加载过程

    实际上jvm对class文件是按需加载的,需要的时候才加载(运行时动态加载),并非一次全部加载进去,jvm启动参数加上:-verbose:class 查看类加载

    package com.nijunyang.spring;
    
    
    /**
     * @author: create by nijunyang
     * @date:2019/6/16
     */
    public class ClassLoaderTest {
        static {
            System.out.println("静态块执行");
        }
        public static void main(String[] args) throws InterruptedException {
            Thread.sleep(3000);
            System.out.println(System.currentTimeMillis());
            new A();
            System.out.println("A对象创建完毕");
            new B();
        }
    }
    

     

    从结果中我们可以看到

    1.从本地/E:/IdeaProject/tuling/spring/target/classes/下面去加载当前运行类ClassLoaderTest.class文件

    2.初始化类,执行静态代码块

    3.main方法运行,睡了5s之后打印当前时间,当我们new A的时候才去本地加载A.class文件到内存,再实例化A

    4.A创建完毕之后,再去加载B.class,完成B的初始化

  • 相关阅读:
    Spring 注解详解01
    java 排序算法
    Java 文件拼接器
    oracle join
    Oracle 去重
    Java 笔试面试
    Oracle 笔试题02
    jvm性能查看常用命令
    关于对JMM(java内存模型)的个人理解
    RSA前端加密后端解密避免出现明文密码
  • 原文地址:https://www.cnblogs.com/nijunyang/p/11037605.html
Copyright © 2011-2022 走看看