一、类加载过程
      执行时机:编译程序——>执行程序(JVM启动、程序运行),类加载发生在程序运行期间

      各个阶段:分为加载阶段、连接阶段(验证、准备、解析)、初始化、使用、卸载

      执行顺序:大体是按以上阶段依次执行,但相互间有交叉
 
                     加载——>验证(文件格式)——>继续加载——>解析——>验证(元数据、字节码)——>准备——>初始化

      参与角色:Class文件、Java虚拟机、类加载器      
                   /**HotSpot的Bootstrap ClassLoader(启动类加载器)是位于虚拟机内部(由C++实现),其它类加载器外置于JVM(由Java实现)*/
 
二、说明—各个阶段
      加载阶段:
           普通类/接口、 数组类(组件类型为基本类型,如int[][]):获取、转化、创建、触发
                   获取——类加载器加载Class文件(指定路径+文件名 ——>确定“全限定名称”——>拿到Class文件(与平台无关的二进制字节流))
                   转化——字节码以一定转化成格式,存放在方法区
                   创建——方法区中生成一个代表这个类的java.lang.Class对象
                   触发——加载的同时,会触发父类、关联引用类的加载
                                             class A extends B————>Class<B>
                               private Class<Person> class————>Class<Person> 
                               Class c =Person.getClass(); ————>Class<Person>                             

1.关于“类加载器”和“生成的这个Class对象”:       1)类加载器              Bootstrap Loader(启动类加载器)、Extended Loader(标准扩展类加载器ExtClassLoader)、AppClass Loader(系统类加载器/应用程序类加载器AppClassLoader)                   启动类加载器:                         目的:加载java_home\lib目录下的字节码文件(如:rt.jar,含有java.lang.Object等基本类)  具体有哪些文件及加载顺序?                          方式:加载System.getProperty("sun.boot.class.path")所指定的路径或jar,在使用Java运行程序时,也可以指定其搜索路径,例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld                                 参考:http://www.cnblogs.com/ITtangtang/p/3978102.htm
               标准扩展类加载器:                         目的:加载java_home\lib\ext目录下的字节码文件
                         方式:加载System.getProperty("java.ext.dirs")所指定的路径或jar。在使用Java运行程序时,也可以指定其搜索路径,例如:java -Djava.ext.dirs=d:\projects\testproj\classes HelloWorld                         结果:<实现类>sun.misc.Luncher@ExtClassLoader————————<继承关系>ClassLoader>URLClassLoader>AppClassLoader
               应用程序类加载器:                         方式:加载System.getProperty("java.class.path")所指定的路径或jar。在使用Java运行程序时,也可以加上-cp来覆盖原有的Classpath设置,例如: java -cp ./lavasoft/classesHelloWorld                         结果:<实现类>sun.misc.Luncher@AppClassLoader————————<继承关系>ClassLoader>URLClassLoader>AppClassLoader

                  自定义类加载器:                         方式:1)继承java.lang.ClassLoader并重写loadClass方法;2)继承java.lang.ClassLoader并重写findClass方法/**JDK1.2后推荐,原因见下方红色部分*/;                         相关:  
 <一>java.lang.Object
 1.getClass()
 public final native Class<?> getClass();    //拿到运行时的Class对象【通过本地方法】
 /**
  *例子:class-Test>main>
  *                    Class c =Person.getClass();
  */
      /**
        *实现:
        *1)虚拟机启动
        *2)虚拟机类加载——Test.class————加载阶段:方法区>外部接口>new java.lang.Class  //Class<?>
        *3)虚拟机类加载——java.lang.Object————【Test加载阶段】触发
        *3)虚拟机类加载——Person.class    ————【Test加载阶段】触发
        *4)应用程序启动
        *5)调用java.lang.ClassLoader>xxx1()、xxx2().....——返回运行时<Person>Class对象
        */

 <二>java。lang.ClassLoader
       1.loadClass(String name, boolean resolve)  /**加载指定名称(包括包名)的二进制类型,同时指定是否解析*/
         loadClass(String name)
     protected Class<?> findClass(String name) throws ClassNotFoundException {   //空方法
         throw new ClassNotFoundException(name);
     }
     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;
         }
     }

 <三>java.lang.Class
      1.getClassLoader()
 /**例子:class-Test>main>
   *                    Object o =new Object();
   *                       System.out.println(o.getClass().getClassLoader());
                                                                    结果>java.lang.NullPointerException
   */
      /**
       *Returns the class loader for the class.
       *This method will return null in such implementations if this class was loaded by the bootstrap class loader.
       *如果没有指定classLoader就默认返回bootstrap classLoader(启动类加载器),因为这个bootstrap classLoader
       *用户拿不到实例,所以返回null表示返回的是bootstrap classLoader
       */
 native ClassLoader getClassLoader0();      //拿到类加载器【通过本地方法】
 public ClassLoader getClassLoader() {
         ClassLoader cl = getClassLoader0();
         if (cl == null)
             return null;
         SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
         }
         return cl;
     }         2.指定类加载器加载类           Class.forName(name, initialize, loader)
       2)与“生成的Class对象”关系              同一Class文件只有被同一类加载器加载,才能判断为相等————>相等的意义在于:1)不相等,会生成多个Class对象;相等,只会生成一个Class对象                                                                             2) 只有同一个Class对象,equals()、isAssignabaleFrom()、instanceof、isInstance()返回结果才相同;
       3)双亲委派模型                                          关系?                              上一级持有下一级的一个引用,属于 has A关系                          分工?(为什么叫双亲委派)                              一个类加载器收到了类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给上一层的类加载器去完成。只有当上级加载器在搜索范围找不到所需类,无法完成这个加载请求时,下级加载器才会尝试自己去加载                           好处?                              Java类随着它的类加载器一起具备了一种优先级的层次关系


2.加载“类/接口”的策略:         非数组类/接口、数组类(组件类型为基本类型,如int[][]):               加载生成代表这个类的java.lang.Class对象后,将在类加载器的“类名称空间”上标识为“已加载”(因为前面已经讨论了,同一Class文件对应同一个类加载器才确定生成的是同一个Class对象)
           数组类(组件类型为引用类型,如Person[][])、非数组类/接口:
                 递归加载组件类型,每次去掉一个维度

连接阶段:

验证——文件格式、元数据、字节码

准备——在方法区为类变量分配内存并初始化

例子                     编译时期                                                             (类加载时)验证阶段—准备时期

static int i =20;             产生constantValue属性,但不会存入常量20                       常规方式进行准备:初始化、分配内存

结果—————>        无                                                                                    0

final static int i =20;             产生constantValue属性,并存20到constantValue               从对应constantValue取出来初始化

结果—————>       20                                                                                   20

解析——将运行时常量池的符号引用替换为直接引用(指向内存目标的句柄),这一过程又叫“静态绑定/静态连接”

      初始化阶段:(动态绑定/动态连接)
              1. 执行时机——主动引用(new、反射、父类、执行主类包含main方法、调用静态方法
                  *new
                           ——执行父类的<clinit>()、执行本类的<clinit>()、执行父类的<client>、执行本类的<client>
 //例子(笔试常考题目)
 public class Father {

 private static int i =20;
 static{
     System.out.println("Father;(类构造器-before)"+i);
     i =50;
     System.out.println("Father;(类构造器-after)"+i);
 }
 public Father() {
     System.out.println("Father:(实例构造器)"+ }

 }

 public class Son extends Father{

     private static int i =20;
     static{
         System.out.println("Son;(类构造器-before)"+i);
         i =50;
         System.out.println("Son;(类构造器-after)"+i);
     }
     public Son() {
         System.out.println("Son:(实例构造器)"+     }
 }

 public class Main {

     public static void main(String[] args) {
         new Son();

     }

 }

 //输出结果:
         /**
            *Father;(类构造器-before)20
            *Father;(类构造器-after)50
            *Son;(类构造器-before)20
            *Son;(类构造器-after)50
            *Father:(实例构造器)50
            *Son:(实例构造器)50
            */
                   2.主动引用、被动引用 
                            被动引用——会发生类加载,但不会初始化
                                         ——例子:略

读《深入理解Java虚拟机》有感——第二部分:虚拟机类加载机制的更多相关文章

  1. 深入理解Java内存模型中的虚拟机栈

    深入理解Java内存模型中的虚拟机栈 Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域,这些区域都会有各自的用途,以及创建和销毁的时间,有的区域会随着虚拟机进程的启 ...

  2. Java基础 -- 深入理解Java类型信息(Class对象)与反射机制

    一 RTTI概念 认识Claa对象之前,先来了解一个概念,RTTI(Run-Time Type Identification)运行时类型识别,对于这个词一直是 C++ 中的概念,至于Java中出现RT ...

  3. (转)《深入理解java虚拟机》学习笔记6——类加载机制

    Java虚拟机类加载过程是把Class类文件加载到内存,并对Class文件中的数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型的过程. 在加载阶段,java虚拟机需要完成以下 ...

  4. Java程序员的必备知识-类加载机制详解

    类加载器的概念 类加载器是一个用来加载类文件的类. Java源代码通过javac编译器编译成类文件.然后JVM来执行类文件中的字节码来执行程序.类加载器负责加载文件系统.网络或其他来源的类文件. JV ...

  5. JVM虚拟机内存溢出垃圾收集及类加载机制总结

    1.Java内存区域与内存溢出异常 虚拟机栈:为虚拟机执行Java方法服务 本地方法栈:为虚拟机使用到的native方法服务. Java堆:是Java虚拟机所管理的内存中最大的一块,被所有线程共享的一 ...

  6. 深入理解Java虚拟机(第2版) 笔记目录

    本篇为读深入理解Java虚拟机(第2版)一书的笔记目录. Java 运行期数据区 Java 垃圾回收算法 Java 内存分配策略 Java 类文件结构 Java 加载.链接.初始化 Java 类加载器

  7. 深入理解Java虚拟机(八)——类加载机制

    是什么是类加载机制 Java虚拟机将class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程就是类加载机制. 类的生命周期 一个类从加载到内存 ...

  8. 全面理解Java内存模型(JMM)及volatile关键字(转载)

    关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型(@Annotation) 深入理解Java类加载器(ClassLoad ...

  9. 全面理解Java内存模型(JMM)及volatile关键字(转)

    原文地址:全面理解Java内存模型(JMM)及volatile关键字 关联文章: 深入理解Java类型信息(Class对象)与反射机制 深入理解Java枚举类型(enum) 深入理解Java注解类型( ...

随机推荐

  1. 【学习整理】NOIP涉及的数论 [updating]

    扩展欧几里得 求二元一次不定式方程 的一组解. int exgcd(int a,int b,int &x,int &y) { int t; ;y=;return a;} t=exgcd ...

  2. LCA算法倍增算法(洛谷3379模板题)

    倍增(爬树)算法,刚刚学习的算法.对每一个点的父节点,就记录他的2k的父亲. 题目为http://www.luogu.org/problem/show?pid=3379 第一步先记录每一个节点的深度用 ...

  3. ArrayList、Vector、HashMap、HashTable、HashSet的默认初始容量、加载因子、扩容增量

    这里要讨论这些常用的默认初始容量和扩容的原因是: 当底层实现涉及到扩容时,容器或重新分配一段更大的连续内存(如果是离散分配则不需要重新分配,离散分配都是插入新元素时动态分配内存),要将容器原来的数据全 ...

  4. linux backlog深入剖析以及netty设置backlog

    netty不同于socket,其上次API没有提供设置backlog的选项,而是依赖于操作系统的somaxconn和tcp_max_syn_backlog,对于不同OS或版本,该值不同,建议根据实际并 ...

  5. C++ 面向对象的三个特点--多态性(一)

    C++的多态性定义 所谓多态性就是不同对象收到相同的消息产生不同的动作.通俗的说,多态性是指一个名字定义不同的函数,这些函数执行不同但又类似的操作,即用同样的接口访问功能不同的函数,从而实现“一个接口 ...

  6. css3属性小结

    /*border-radius*/ .demo2{ border:2px solid #a1a1a1; padding:10px 40px; background:#dddddd; width:300 ...

  7. ajax使用

    ajax基本使用 ajax在我们的开发中是必须使用的一个技术,ajax即异步的javascript和xml但是现在我们通常使用json来完成数据的交互,ajax职责很单一就是数据的交互,发送数据接收数 ...

  8. 换SSD硬盘,重装系统,一阵子忙乱

    许久没重装过系统了,低声下气地问老板要了一块SSD硬盘,不马上安装上手痒得难受,但年底这个时候重装系统绝对忙乱,差点耽误了一份申请表和一份培训记录表.   SSD安装:先从网上找相关贴子,最主要的一个 ...

  9. 【读书笔记】iOS-UIFont-如何知道字体的PostScript名称

    一,名词解释 PostScript字体: 按 PostScript 页面描述语言 (PDL) 规则定义的字体,并且只能在 PostScript 兼容的打印机上打印. 二,打开Launchpad---- ...

  10. HTML5--Audio

    一.Audio标签 Web 上的音频 直到现在,仍然不存在一项旨在网页上播放音频的标准. 今天,大多数音频是通过插件(比如 Flash)来播放的.然而,并非所有浏览器都拥有同样的插件. HTML5 规 ...