Java——类加载与反射

一、类的加载过程

当程序主动使用某个类时,如果该类还未被加载到内存中,系统会通过加载、链接、初始化三个步骤来对该类进行初始化,这三个步骤统称为类加载。

加载:load

就是指将类型的class字节码数据读入内存

链接:link

链接分为三步

① 验证

校验被加载的class文件的合法性,并且不会危害虚拟机的自身安全(文件格式验证,语义分析等)

② 准备

为类变量分配内存(在方法区中)并设置初始值(0,null,false),为静态常量赋初始值(常量池中)

③ 解析

把字节码中的符号引用替换为对应的直接地址引用

初始化:initialize

为类的静态变量赋予正确的初始值,JVM负责对类进行初始化,主要对类变量进行初始化。
类初始化执行的是<clinit>(),该方法会执行
①类变量的显式赋值代码
②静态代码块中的代码

二、哪些操作会导致类的初始化?

  • loaderClass, forName等
  • java.exe 命令运行的类
  • 使用 new 创建类的实例
  • 访问类的静态变量,调用类的静态方法
  • 初始话其子类
  • 使用反射创建类

三、类加载器

Java类如何加载到内存中?类的加载通过类加载器完成。JVM启动会先创建类加载器ClassLoader对象用来加载Java类。

类加载器分类

  • 引导类加载器(Bootstrap ClassLoader) 又称为根类加载器
    它负责加载 jre/lib/rt.jar 核心库
    它本身不是Java代码实现的(HotSpot VM 中C++实现的),也不是ClassLoader的子类,获取它的对象时往往返回null

  • 扩展类加载器(Extension ClassLoader)
    它负责加载 jre/lib/ext 扩展库
    它是 ClassLoader 的子类
    Java 代码编写

  • 应用程序类加载器(Application ClassLoader)
    也称为系统类加载器 System Class Loader
    它负责加载项目的 classpath 路径下的类
    它是ClassLoader的子类
    Java 代码编写

  • 自定义类加载器
    当你的程序需要加载“特定”目录下的类,可以自定义类加载器,必须继承自java.lang.ClassLoader类
    当你的程序的字节码文件需要加密时,那么往往会提供一个自定义类加载器对其进行解码
    tomcat服务器中会应用到
    小知识
    ClassLoader.getSystemClassLoader方法无论何时均会返回ApplicationClassLoader,其只加载classpath下的class文件。

    在javaSE环境下,一般javaSE项目的classpath为bin/目录,因此只要编译后的class文件在classpath下就可以。此时ApplicationClassLoader就可以加载动态生成的类。

    但在javaEE环境下,我们的项目里的类是通过WebAppClassLoader类来加载的,此时我们获取了ApplicationClassLoader,因此自然找不到class文件。

Java系统类加载器的双亲委托模式

在JVM虚拟机中,如果一个类加载器收到类加载的请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器完成。每个类加载器都是如此,只有当父加载器在自己的搜索范围内找不到指定的类时,子加载器才会尝试自己去加载,自己也加载不了那么会抛异常(即ClassNotFoundException)。
对于每个类加载器,只有父类(依次递归)找不到时,才自己加载 。这就是双亲委派模式

① 这样可以避免重复加载
​ 前面已经说明,当一个类要加载时先看父级类加载器是否加载,如果已经加载过,则无需再重复加载。

② 考虑到安全因素
​ 假设我们使用一个第三方Jar包,该Jar包中自定义了一个java.lang.String类,它的功能和系统String类的功能相同,但是加入了恶意代码。那么,JVM会加载这个自定义的String类,从而在我们所有用到String类的地方都会执行该恶意代码。如果有双亲委派模型,自定义的String类是不会被加载的,因为最顶层的类加载器会首先加载系统的java.lang.String类,而不会加载自定义的String类,防止了恶意代码的注入。

获取类加载器的方式

//获取当前类的加载器
ClassLoader classLoader = Demo.class.getClassLoader();
//获取当前线程上下文类加载器
ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
//获取系统类加载器
ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();

四、java.lang.Class类

万物皆对象,每个类编译后生成的字节码文件,即class文件,在类加载后JVM会为每个class文件创建一个对象,也就是Class类的一个对象。这个Class对象封装了类在方法区内的数据信息

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制。

获取Class对象的四种方式

  1. 类型名.class
    要求编译期间已知类型,所有的Java类型都可通过此方式获取Class对象

  2. 对象.getClass()
    获取对象的运行时类型

  3. Class.forName(类型全名称)
    可以获取编译期间未知的类型

  4. ClassLoader的类加载器对象.loadClass(类型全名称)
    可以用系统类加载对象或自定义加载器对象加载指定路径下的类型

五、反射

可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值