类的加载及反射小结

类的加载

  • 何为类的加载?

    • 类的加载,将class文件的二进制数据加载进内存中,将其放进jvm的运行时数据区,由堆创建java.lang.class对象,用来封装类在方法去的数据结构
    • 类的加载时机与过程:一个类从被加载进虚拟机到卸载出内存,有如下的生命周期:加载,验证,准备,解析,初始化,使用,卸载。其中验证,准备,解析被称为连接。
    • 加载,解析,准备,初始化,卸载的顺序是一定的。而解析不一定,可以在初始化之后进行。这是为了java的运行动态绑定
    • 加载的过程:
      • 通过全限定类名,获取该类的二进制字节流
      • 将二进制流的静态存储结构转换为方法区运行时数据结构
      • 在内存生成对应的java.lang.class对应的class对象,作为方法区这个类的各种数据访问入口
    • 验证
      • 文件格式验证
      • 元数据验证
      • 字节码验证
      • 符号引用验证
    • 准备
      • 为类变量,一般为static修饰的变量赋初始值,实例变量将在对象初始化时在堆中赋值。
    • 解析
      • 将常量池的符号引用变为直接引用。
    • 初始化
      • 初始化变量和其他资源
  • ClassLoader的概念

  • java程序在运行时,Jvm通过类加载器(classLoader)加载进内存。

  • ClassLoader的分类

    • Bootstrap ClassLoader:启动类加载器
    • Extension ClassLoader:扩展类加载器
    • Application ClassLoader:应用程序类加载器(一般自己写的类)
  • 有且只有五种类型必须对类初始化

    • 遇到 new, getstatic, putstatic, invokestatic 这些字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。生成这4条指令的最常见的Java代码场景是:使用new关键字实例化对象的时候、读取或设置一个类的静态字段(被final修饰、已在编译器把结果放入常量池的静态字段除外)的时候,以及调用一个类的静态方法的时候。

    • 使用 java.lang.reflect 包的方法对类进行反射调用的时候,如果类没有进行过初始化,则需要先触发其初始化。

    • 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。

    • 当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。

    • 当使用jdk1.7动态语言支持时,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果REF_getstatic, REF_putstatic, REF_invokeStatic 的方法句柄,并且这个方法句柄所对应的类没有进行初始化,则需要先出触发其初始化。

双亲委派模型

  • 概念:当一个类加载器要加载一个类,那么它便会委派给上一层的类加载器去加载,当最顶层的类加载器未找到该类,则层层返回,直到由起初委派他人的这个类加载器自己去寻找类,如果没有找到则会弹出ClassNotFoundException。

双亲委派模型的破坏

  • 由于com.mysql.jdbc.Driver不在/lib目录下,导致启动类加载器,无法加载到mysql这个类,这就是双亲委派模型的局限性,父类加载器无法加载子类加载器路径下的类。

  • 所以我们有线程上下文类加载器,能达到父类加载器加载子类加载器路径下的类,但这破坏了双亲委派模型。

  • jvm的热部署

    • 热部署:在不重启虚拟机的情况下,能自动侦测到class文件发生了变化,更新运行时class行为。

    • 由于一个类是通过类加载器加载到虚拟机,生成对应的class对象。之后可以实例化对象。而当一个的class文件发生变化,热部署检测到了,便会新建一个加载器重新加载class文件。

手写自定义加载器

反射

  • 概念:反射就是动态加载对象,并对对象进行剖析。在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能成为Java反射机制。
  • 反射的小栗子
    • 写一个简易的实体类
    • 通过全限定类名反射加载得到class对象。并且实例化一个对象
  • 反射的优势:提高了程序的扩展性多用于底层框架,诸如ORM,RPC框架
  • 反射的缺点:性能远不如直接实例化对象来的快。

反射的三种方式

  • 通过Class.forName的静态方法+全限定类名
  • 通过需要获取类的类名.Class
  • 通过实例对象的getClass()方法;

创建对象的两种方式

  • 通过class的newInstance()

  • 通过class的getConstructor()

-------------The End-------------
0%