JAVA安全|基础篇:反射机制之类加载

admin 2022年9月10日15:26:02评论54 views字数 2837阅读9分27秒阅读模式
0x00  前言
    JAVA安全系列文章主要为了回顾之前学过的java知识,构建自己的java知识体系,并实际地将java用起来,达到熟练掌握java编程,并能用java编写工具的目的。此系列文章需要读者具备一定java基础,不定时更新。相关详情可通过我的公众号文章进行查看:
JAVA安全|即将开启:java安全系列文章
    反射部分文章内容,主要来自B站韩顺平老师JAVA基础课的反射讲解部分,链接:
https://www.bilibili.com/video/BV1fh411y7R8?p=711&vd_source=f50eede57052ba3346254570c978a2ee
本文为JAVA安全系列文章第五篇。

0x01  类加载的认识
在前面的学习中,我们说类加载器会将.class字节码文件进行加载,从而在堆中产生该类的Class对象及在方法区中生成该类的字节码二进制数据(元数据)。本文我们将对类加载这个过程进行进一步学习,对应于Java反射机制原理图中的这个部分:
JAVA安全|基础篇:反射机制之类加载
1.静态和动态加载
反射机制是Java实现动态语言的关键,也就是说通过反射实现类的动态加载。
(1)静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
代码示例:
JAVA安全|基础篇:反射机制之类加载
上面这段代码里,使用new的方式创建对象且没有定义Dog类,使用javac进行编译时,由于找不到Dog类,所以会报错:
JAVA安全|基础篇:反射机制之类加载
编译时加载相关的类,即静态加载。
(2)动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,则不报错,降低了依赖性。
示例代码:
JAVA安全|基础篇:反射机制之类加载
使用了反射机制来创建对象且没有定义Dog类,javac编译通过且运行时只有当需要Dog类时才会报错:
JAVA安全|基础篇:反射机制之类加载
运行期间需要时才加载所需要的类,即为动态加载。
可以将静态加载理解为及时性加载,动态加载理解为延时性加载。

2.类加载时机
类加载会发生在以下四种时候:
(1)当创建对象时(new)
(2)当子类被加载时,父类也加载
(3)调用类中的静态成员时
(4)通过反射
前面三种均为静态加载,第四种为动态加载。

3.类加载过程
类的加载分为三个阶段:加载(Loading),连接(Linking),初始化(initialization)。而连接阶段又分为三个小阶段:验证(verification),准备(Preparation),解析(Resolution)。故也可以说类加载过程由五个阶段组成
类加载过程图如下:
JAVA安全|基础篇:反射机制之类加载

4.类加载各阶段完成任务
(1)加载阶段:负责将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类加载器完成。
(2)连接阶段:负责将类的二进制数据合并到JRE中。
(3)初始化阶段:JVM负责对类进行初始化,这里主要指静态成员。
前两个阶段完全由JVM机来控制,第三个阶段由程序员来控制。
JAVA安全|基础篇:反射机制之类加载

0x02  类加载的五个阶段详解
1.加载阶段(Loading)
JVM在该阶段的主要目的是将字节码从不同的数据源(可能是class文件、也可能是jar包,甚至网络)转化为二进制字节流加载到内存中((即方法区的字节码二进制数据/元数据)),并生成一个代表该类的java.lang.Class对象(即堆中的Class对象,是一种数据结构,可理解为结构化数据)

2.连接阶段-验证(Linking-verification)
(1)目的是为了确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并且不是危害虚拟机自身安全。
说明:new对象时debug源码,两次force step into可看到会由系统创建一个SecurityManager对象来进行检查:
JAVA安全|基础篇:反射机制之类加载
(2)检查内容包括:文件格式验证(是否以魔数 0xcafebabe开头)、元数据验证、字节码验证和符号引用验证。
说明:一个正常的.class后缀文件以16进制打开是以0xcafebabe开头的:
JAVA安全|基础篇:反射机制之类加载
(3)可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间。
注:在大项目中由于加载的类会比较多,可能会用到这个。

3.连接阶段-准备(Linking-Preparation)
JVM会在该阶段对静态变量分配内存并默认初始化(对应数据类型的默认初始值,如0、0L、null、false等)。这些变量所使用的内存都将在方法区中进行分配。
说明代码:
JAVA安全|基础篇:反射机制之类加载

4.连接阶段-解析(Linking-Resolution)
虚拟机将常量池内的符号引用替换为直接引用的过程。
说明:比如有A、B两个类,A类引用了B类,当类加载还未将类放入内存中时,由于没有内存地址,记录的是A和B的相对引用关系,称符号引用;当将类加载到内存中后,有了内存地址,引号关系就用分配的地址来表示,称直接引用。

5.初始化(Initialization)
(1)到初始化阶段,才真正开始执行类中定义的Java程序代码,此阶段是执行<clinit>()方法的过程。(该阶段由程序员来控制了)
(2)<clinit>()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。
说明代码:
JAVA安全|基础篇:反射机制之类加载
(3)虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的<clinit>()方法,其他线程都需要阻塞等待,知道活动线程执行<clinit>()方法完毕。
说明:我们new一个对象来debug一下,一路force step into,直到:
JAVA安全|基础篇:反射机制之类加载
synchronized表示这里使用了线程同步机制,会检查当前这个类是否已经被加载,涉及到操作系统方面的知识了。正因为有线程同步机制,才能保证某个类在内存中, 只有一份Class对象。
类加载机制再深入就涉及到JVM底层了,作为安全学习,反射机制的学习,类加载学习到此处足以。

0x03  总结
    本文学习了动态和静态加载、类加载的时机,以及类加载的五个阶段都发生了什么。主要就是一些概念和原理方面的东西。应重点理解动态加载及类加载五个阶段所发生的事。
    反射机制的学习主要包含两块:原理和应用。原理就是Java反射机制原理图的前两个阶段,花了三篇文章来对相关概念和原理进行学习,应重点掌握这部分;应用就是原理图的第三个阶段了,主要就是API调用。理解了原理才能更好地去应用。
下一篇是Java反射机制学习的最后一篇,主要是敲代码练习常用的API。

Java安全系列文集

第0篇:JAVA安全|即将开启:java安全系列文章

第1篇:JAVA安全|基础篇:认识java反序列化

第2篇:JAVA安全|基础篇:实战java原生反序列化

第3篇:JAVA安全|基础篇:反射机制之快速入门

第4篇:JAVA安全|基础篇:反射机制之Class类

如果喜欢小编的文章,记得多多转发,点赞+关注支持一下哦~,您的点赞和支持是我最大的动力~

原文始发于微信公众号(沃克学安全):JAVA安全|基础篇:反射机制之类加载

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年9月10日15:26:02
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   JAVA安全|基础篇:反射机制之类加载http://cn-sec.com/archives/1289566.html

发表评论

匿名网友 填写信息