JavaSE 反射 入门

1. 前言


· 本文章是用于 个人学习过程中 整理知识点的帖子,主题为:JavaSE 反射 入门

· 本文章出现的 遗漏、错误 欢迎点开这篇文章的各位指出。

· 本文章的知识大纲根据 韩顺平老师 JavaSE 教学视频 进行编写。

感谢韩顺平老师带来的优质教学和对教育作出的贡献


2. 反射的引入


场景模拟

· 假设现在有一个类,其中包含一些方法,我们如果需要调用这些方法。我们会创建类对象,并调用方法。

· 当我们要调用类的其他方法,我们会 重新编写源代码 。但如果此时不允许我们动用源代码且调用相关方法时,我们应该怎么做?

· 此时就引出了 反射 的概念 。

基本特点

· 反射是指:不动用源代码的基础上,扩展和使用类只通过读取配置文件来实现类的调用

· 反射的最大特点就是,开闭模式:对类的访问是开放的、对类内部结构是关闭的

基本使用

在这里插入图片描述


3. 反射原理


Java程序 三大阶段

· 在介绍反射机制前,我们先引出 Java 程序的三大阶段:编译阶段、加载阶段、运行阶段

  1. 编译阶段:编写类、类变量、方法、构造器 等一系列类成员对象。这些类会被 Javac 进行编译,从 Java 文件 变为 class 字节码文件

  2. 加载阶段:类加载器 ClassLoader 会通过 loadClass() 方法class 字节码文件 加载成 Class 类对象 并放到堆中,每一个 Class 类对象 会将各个成员对象封装到各自的集合中,例如:成员变量 放在 Field 数组、构造器 放在 Constructor 数组、成员方法 放在 Method 数组 。。。

  3. 运行阶段:通过编写创建类对象、调用方法的代码后,在 堆 中 创建 类对象,此时这个类对象会指向类加载器 在 堆 中加载完毕的 Class 类对象 。此时两者产生了连通关系,即 通过创建类对象,获取相应的 Class 类对象,从而实现相应的操作。

图解

图片来源:@韩顺平教育

在这里插入图片描述


反射机制

· 反射机制就体现在 加载阶段,即类加载器加载 class 文件 创建 Class 类对象阶段 。

· 反射机制在运行阶段时可以实现:

   1. 判断任意一个对象所属的类 。

   2. 构造任意一个类对象 。

   3. 得到任意一个类所具有的的成员变量和方法 。

   4. 调用任意一个对象的成员变量和方法 。

   5. 生成动态代理 。


· 反射的优点:可以动态的创建和使用对象【这也是框架底层的核心】,使用灵活 。

· 反射的缺点:使用反射基本是解释执行,对执行速度有一定影响 。


4. 相关类


基本介绍

· java.lang.Class :代表一个类,Class对象表示某个类加载后在堆中的对象

· java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法

· java.lang.reflect.Field:代表类的成员变量, Field对象表示某个类的成员变量

· java.lang.reflect.Constructor:代表类的构造方法, Constructor对象表示构造器

· 根据 反射的基本使用 中 我们可以得出结论:

· Method、Field、Constructor 类 都是 基于 Class 类 调出的 类对象 ,但同时又可以独立出来执行更细致的方法

反射优化

· 反射相较于传统的调用类,执行效率会明显降低,这是因为 反射的对象在使用时会执行访问检查

· Method、Field、Constructor 类对象 提供了 setAccessible() 方法 .

· 这个方法的作用是:启动和禁用访问安全检查的开关True 为 关闭 ,False 为开启 】


5. Class类


类结构体系
在这里插入图片描述

基本介绍

· Class 类对象 本身也是一个类,因此它也继承 Object 类 。

· Class 类对象是从系统中创建出来的 。

· 对于某一个类的 Class 类对象,在内存中只有一份,因为类只加载一次 。

· 每个实例类都会记得自己由哪一个 Class 对象实例所生 。

· Class 类对象可以完整的得到一个类的完整结构 。

· Class 类对象是存放在堆的 。

· 类的字节码二进制数据,是放在方法区的。【例如,方法代码、变量名、方法名、访问权限】

相关方法

相关方法解释
forName ( String name )返回指定类名name的Class对象
newlnstance ( )调用缺省构造函数,获取该 Class对象 的一个实例
getPackage ( )获得 包
getName ( )返回对象各类成员的 名称
getlnterfaces ( )获取当前 Class对象 的 接口
getClassLoader ( )返回该类的 类加载器
getConstructors ( )返回 Constructor 对象 数组
getField ( String name )根据属性名返回 Field 对象
getFields ( )返回 Field 对象 数组

获取方法

· 获取 Class 类对象 的方式有六种:

   1. 在已知全类名,且该类在类路径下时,可以使用 forName ( ) 静态方法 。

   2. 若已知具体的类,则直接通过 class 方法 。【基本数据类型也可使用】

   3. 在已知某个类的实例,直接调用 getClass ( ) 方法 。

   4. 通过某个类的实例,先获取 Class 类对象,然后获取该对象对应的 类加载器:getClass ( ).getClassLoader ( ) 然后再调用 loadClass ( ) 方法获得类【该方法需传入类全名参数】

   5. 若目标类是基本数据类型的包装类,可通过 TYPE 方法 获得 。


6. 类加载


基本介绍

· 类加载分为两种:静态加载、动态加载

· 静态加载: 在编译时加载类对象,如果类不存在,则在编译期间报错【例:Dog dog = new Dog()

· 动态加载: 在运行时加载类对象,当执行到要加载相关类的时候,再进行加载操作【例:反射】


类加载时机

· 创建对象时【例:new】

· 当子类被加载时,父类也加载 。

· 调用类中的静态成员时 。

· 通过反射 。

类加载过程
在这里插入图片描述
在这里插入图片描述

类加载的三大阶段 详解

  1. 加载阶段

    JVM 在该阶段的主要目的是 将字节码从不同的数据源转化为二进制字节流 ,并加载到内存中,同时生成一个代表该类的 java.lang.Class 对象 。【字节流会放在方法区中,而Class对象会放在堆中】

  2. 连接阶段

    a. 验证:包括文件格式(是否以魔数 oxcafebaba 开头)、元数据、字节码和符号引用验证 。
    【目的是为了确保 Class 文件 的字节流包含的信息符合当前虚拟机的要求,且不会危害虚拟机自身的安全】
    【可通过-Xerify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载时间】

    b. 准备:JVM 会在该阶段对静态变量分配内存并初始化,这些变量使用的内存都将在方法区中进行分配 。

    c. 解析:是虚拟机将常量池内的符号引用替换为直接引用的过程 。

  3. 初始化阶段

    该阶段真正开始执行类中定义的 Java 程序代码,此阶段是执行<clinit>() 方法的过程。

    a. <clinit>() 方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有 静态变量 的赋值动作 和 静态代码块 中的语句,并进行合并。

    b.虚拟机会保证一个类的 <clinit>() 方法在多线程环境中被正确的加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的 <clinit>() 方法,其他线程都需要阻塞等待,直到活动线程执行完成 。


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值