反射复习(java)

文章目录

  • 反射机制的作用
  • 反射机制的原理
    • 加载机制详细解释
  • 获取 Class 对象
  • 反射获取构造方法:获取 Class 对象里面 Constructor 对象
  • 反射获取成员变量:获取Class 对象里面的 Field 对象
  • 反射获取成员方法:获取 Class 对象里的 Method 对象
  • 其他常用 API

前言

反射非常重要,一定要掌握,我个人觉得不是很难,就是要注意各种方法里的参数是什么,然后还是那句话:最快的入门方式是看视频,建议先看完视频,再来看博客,这里我推荐 b 站韩顺平老师的视频

反射机制的作用

作用看不懂的话可以最后看

反射可以在不修改源码的情况下来控制程序符合 ocp 原则 :不修改源码,扩容功能


举个例子

现在有一个 main 类 和 Person 类,还有一个配置文件my.Properties,可以利用反射通过中间的 my.Properties 访问类中的东西

my.Properties

Classfullpath = com.mangfu.Person
field = name

Person

public class Person {public String name = "jack";public int age = 13;public Person() {};public Person(String name, int age) {this.name = name;this.age = age;}}

Main

public class Main {public static void main(String[] args) throws Exception{//导入配置文件Properties properties = new Properties();properties.load(new FileInputStream("src/com/mangfu/my.Properties"));//通过配置文件获取 类的完整路径, 和类的属性名String classfullpath = properties.getProperty("Classfullpath");String field = properties.getProperty("field");//通过反射获取到 Person类的字节码对象,我们可以操作里面所有的东西Person person = new Person();Class clazz = Class.forName(classfullpath);//这里直接操作类里面的属性//本来是要 person.name 改成 person.age//现在直接在配置文件中的 name 改成 age就行了Field field1 = clazz.getField(field);System.out.println(field1.get(person));}
}

可以看见我们可以通过中间的 配置文件 无需修改源码,就能操作类中的信息




反射机制的原理

在这里插入图片描述

编译的时候会产生字节码文件,然后通过类加载器,进入加载阶段,会在堆区创建一个 Class 类的对象,当然这个Class对象里面的成员变量,构造器,构造方法等东西都是对象,然后 到 new Cat(),在 堆区创建 Cat 对象,该对象知道他属于哪个 Class 对象,我们可以通过反射得到这个 Class 对象,然后操作类中的所有东西

注意一个类只有一个 Class 对象



加载机制详细解释

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


Loading(加载)

JVM 将 字节码文件 从 不同 的 数据源,转化为 二进制字节流,加载到内存中,生成一个代表该类的 Class 对象,也就是这个类的对象


verification(验证)

为了确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,,不会危害虚拟机自身的安全,这个阶段会 进行文件格式验证 **(是否以魔数 oxcafebabe开头),元数据验证,字节码验证,和符号引用验证

如果想要关闭大部分类验证措施,加快加载速度可以这样做

javac -Xverify:none HelloWorld.java

helloworld 是类名


Preparation(准备)

JVM 会在该阶段 对 静态变量!!!,分配内存并初始化(对应数据类型的默认初始值)。这些变量的 内存分配在方法区

注意这里是静态变量,不是静态的,加载阶段不会分配内存


Resolution (解析)

JVM 将常量池的 == 符号引用== 替换为 直接引用的过程

符号引用

将 Java 类文件中,以一组符号来描述类名,方法名等东西,这些符号与实际的内存地址没有关系

直接引用

将符号引用,直接替换为直接指向这些数据的指针或地址

还没分配内存的时候用符号引用类似于打个标记,这个时候分配内存在变成直接引用


initialization(初始化)

这个阶段才真正执行类中定义的 Java 程序代码,这个阶段也是执行 clinit() 方法的过程,这个方法会根据顺序,把静态变量的赋值动作,和静态代码块中的语句合并

clinit 方法在多线程的环境中会正确加锁,也就是线程是阻塞的,等一个线程 clinit 方法执行完,才放锁,让下一个线程用




获取 Class 对象

  • Class.forName(“全类名”):编译阶段创建
    全类名:包名 + 类名

多用于配置文件,最常用

//com.mangfu.test 包下的 Student 类
Class test = Class.forName("com.mangfu.test.Student" );

  • 类名.class:加载阶段创建,类加载器得到 Class 对象

多用于参数传递,比如通过反射得到对应构造器对象,这种方式 最安全,性能最高

Class clazz = Student.class

  • 对象.getClass():运行阶段创建

通过创建好的对象,获取 Class 对象

Student s = new Student();
Class clazz = s.getClass();

  • 基本数据类型.class

基本数据类型,创建 Class 对象的方法

Class clazz = int.class

  • 包装类.TYPE

基本数据类型对应的包装类,创建 Class 对象的放啊

Class clazz = Integer.class



反射获取构造方法:获取 Class 对象里面 Constructor 对象

Class类 中用于获取构造方法的方法

  • Constructor<?>[] getConstructors(): 返回所有公有构造方法对象的数组

  • Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组

  • Constructor getConstructor(Class<?>… parameteTypes):返回单个公有构造方法对象
    参数为 基本数据结构或者包装类的字节码,对象.class,这样可以获取有参构造

  • Constructor getDeclaredConstructor(Class<?>…parmeterTypes):返回单个构造方法对象
    参数为 基本数据结构或者包装类的字节码,对象.class,这样可以获取有参构造

Constructor:用构造方法对象创建对象的方法
Student类

  • T newinstance(Object…initargs):根据指定的构造方法创建对象
    参数(可变):是构造函数里面需要的参数

  • setAccessible(boolean flag):设置为 true, 表示取消访问检查

setAccessible:**使用反射可以访问 private 构造器 [称为爆破]


举个例子
主要看Main类

Student类

public class Student {private int age = 18;public String name = "张三";private Student() {}private Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}
}

Main 类

public class Main {public static void main(String[] args)throws Exception {Class clazz = Class.forName("com.mangfu.test.Student");//因为 构造方法是私有的 所以我们要用 getDeclaredConstructor//里面的参数是 形参的字节码Constructor cs = clazz.getDeclaredConstructor(int.class, String.class);//因为这个是私有对象,我们要通过爆破创建才能构造一个对象cs.setAccessible(true);//通过 newInstance 构造一个对象Student s = (Student) cs.newInstance(18, "张三");System.out.println(s);}
}


反射获取成员变量:获取Class 对象里面的 Field 对象

Class 类中用于获取成员变量的方法

  • Field[] getFields():返回所有公共成员变量对象的数组

  • Field[] getDeclaredFields():返回所有成员变量对象的数组

  • Field[] getField(String name):返回单个公有成员变量对象
    参数是 对象(不是Class对象,下面是Student 对象) 的属性名

  • Field getDeclaredField(String name):返回单个成员变量对象
    参数是 对象(不是Class对象,下面是Student 对象) 的属性名

Field 类中用于创建对象的方法

  • void set(Object obj, Object value):赋值
    参数1:field 对象,参数2:需要赋的值

  • Object get(Object obj):获取值
    参数:对象(不是Class 对象,下面是 Student 对象)的名字

  • setAccessible(boolean flag):设置为 true, 表示取消访问检查

举例
Student 类

public class Student {private int age = 18;private String name = "张三";private Student() {}private Student(int age, String name) {this.age = age;this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}
}

Main类

public class Main {public static void main(String[] args)throws Exception {//得到 Student 类的 Class 对象Class clazz = Class.forName("com.mangfu.test.Student");//获取 Class 对象里面的 Field 对象----属性 nameField field = clazz.getDeclaredField("name");//通过 反射利用构造函数构造对象Constructor cs = clazz.getDeclaredConstructor(int.class, String.class);cs.setAccessible(true);Student s = (Student) cs.newInstance(18, "张三");//因为这个属性是私有的 所以要用 setAccessible 爆破一下,才能修改field.setAccessible(true);//修改 属性 name 的 值,因为上面我们获取的 是属性 name 对象field.set(s, "李四");System.out.println(field.get(s));//输出李四}
}


反射获取成员方法:获取 Class 对象里的 Method 对象

Class类中用于获取成员方法的方法

  • Method[] getMethods():返回公有成员方法对象的数组,包括继承的

  • Method[] getDeclaredMethods:返回所有成员方法对象的数组,不包括继承的

  • Method getMethod(String name, Class<?>…parameterTypes):返回单个公有成员方法对象
    参数1:方法的名字,参数2:方法的形参(可变)

  • Method getDeclaredMethod(String name, Class<?>…parameterTypes):返回单个成员方法对象
    参数1:方法的名字,参数2:方法的形参(可变)

Method类中用于创建对象的方法

  • Object invoke(Object obj, Object…args):允许方法
    参数1: 对象(不是Class对象,下面是Student 对象),参数2:调用方法要传递的参数(没有就不写)。返回值:调用的方法的返回值的对象

  • setAccessible(boolean flag):设置为 true, 表示取消访问检查

举例
Student 类

public class Student {private int age = 18;private String name = "张三";public Student() {};private Student(int age, String name) {this.age = age;this.name = name;}private int hi() {System.out.println("调用hi函数");return 1;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}
}

Main 方法

public class Main {public static void main(String[] args)throws Exception {//得到 Student 类的 Class 对象Class clazz = Class.forName("com.mangfu.test.Student");//得到 Student 中的 hi 方法的对象Method method = clazz.getDeclaredMethod("hi");//这里 通过反射 构造 Student 类对象Constructor constructor = clazz.getConstructor();Student s = (Student) constructor.newInstance();//通过反射调用 Student 类中的 hi 方法,因为我们上面的得到的 Method 对象是 hi 方法//而且这个方法是私有的所以要爆破一手method.setAccessible(true);method.invoke(s);}
}



其他常用 API

Class
在这里插入图片描述


Constructor

Parmeter[] getrParmameters():获取构造方法的形参

int getmodifiers():获取成员变量的数据类型


Field

int getmodifiers():获取成员变量的数据类型
Class<?> getType:获取成员变量的数据类型
String getName:获取成员变量的名字


Method

int getmodifiers():获取成员变量的数据类型
Class[] getExceptionTypes:获取方法抛出的异常
String getName:获取成员变量的名字
Class[] getParameter():获取方法的形参,以 Class[] 形式返回
Class getReturnType:以Class 形式获取返回类型


getmodifiers() 方法返回值

默认修饰符号:0,public:1,private:2,protected:3,static:8,final:16




本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/354836.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

python-04

str.spilt() str.spilt(str" ", num string.count(str)); str&#xff1a;分隔符&#xff0c;默认为所有的空字符&#xff0c;包括空格、换行符"\n"、制表符"\t"等。 num&#xff1a;分隔次数 str "小时候 总有他们在耳边叮咛嘱咐 小…

Nginx 搭建 lnmp

一.编译安装Nginx 1.新建用户前期准备 官网下载nginx安装包 https://nginx.org/en/download.html yum -y install gcc pcre-devel openssl-devel zlib-devel openssl openssl-devel #安装依赖包 useradd -M -s /sbin/nologin nginx #新建nginx用户便于管理 2.切换到/opt…

『 Linux 』动态库的加载

文章目录 动静态库的区别动态库-共享库动态库的加载动态库的管理 总结 动静态库的区别 动态库(Dynamic Libraries) 链接方式 动态链接,程序在运行时(而不是在编译时)与动态库链接; 操作系统负责加载动态库文件; 文件大小 使用动态库的应用程序通常其可执行文件大小更小; 因…

FlashDB的TS数据库的标准ANSI C移植验证

本文目录 1、引言2、环境准备3、修改驱动4、验证 文章对应视频教程&#xff1a; 暂无&#xff0c;可以关注我的B站账号等待更新。 点击图片或链接访问我的B站主页~~~ 1、引言 在当今数据驱动的时代&#xff0c;高效可靠的数据存储与管理对于嵌入式系统及物联网(IoT)应用至关重…

Matlab数学建模实战应用:案例2 - 传染病传播

目录 前言 一、问题分析 二、模型建立 三、Matlab代码实现 四、模型验证 灵敏度分析 五、模型应用 实例总结 总结 前言 传染病传播模型是公共卫生和流行病学的重要研究内容&#xff0c;通过数学建模可以帮助我们理解传染病的传播规律和趋势&#xff0c;以便制定有效的…

商超智能守护:AI监控技术在零售安全中的应用

结合思通数科大模型的图像处理、图像识别、目标检测和知识图谱技术&#xff0c;以下是详细的商超合规监测应用场景描述&#xff1a; 1. 员工仪容仪表监测&#xff1a; 利用图像识别技术&#xff0c;系统可以自动检测员工是否按照规范整理妆容、穿着工作服&#xff0c;以及是否…

[Linux] 系统管理

全局配置文件 用户个性化配置 配置文件的种类 alias命令和unalias命令 进程管理 进程表

数电逻辑门电路分析和Digital仿真

文章目录 1. 逻辑门电路 2. 非门&#xff08;NOT Gate&#xff09; 3. 与门&#xff08;AND Gate&#xff09; 4. 或门&#xff08;OR Gate&#xff09; 5. 与非门&#xff08;NAND Gate&#xff09; 6. 或非门&#xff08;NOR Gate&#xff09; 7. 异或门&#xff08;XO…

WPF学习(3)--不同类通过接口实现同种方法

一、接口概述 1.接口的概念 在C#中&#xff0c;接口&#xff08;interface&#xff09;是一种引用类型&#xff0c;它定义了一组方法、属性、事件或索引器&#xff0c;但不提供实现。接口只定义成员的签名&#xff0c;而具体的实现由实现接口的类或结构体提供。接口使用关键字…

【每日刷题】Day70

【每日刷题】Day70 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 922. 按奇偶排序数组 II - 力扣&#xff08;LeetCode&#xff09; 2. 905. 按奇偶排序数组 - 力扣&…

2024年【N1叉车司机】作业考试题库及N1叉车司机实操考试视频

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 2024年N1叉车司机作业考试题库为正在备考N1叉车司机操作证的学员准备的理论考试专题&#xff0c;每个月更新的N1叉车司机实操考试视频祝您顺利通过N1叉车司机考试。 1、【多选题】《中华人民共和国特种设备安全法》第…

Java基础学习-方法

目录 方法基础概念 方法的格式&#xff1a; 案例&#xff1a;最简单方法的定义 案例&#xff1a;带参数的方法调用 案例&#xff1a;求圆的面积 带有返回值的方法&#xff1a; 方法注意点 方法的重载&#xff1a; ​编辑 案例&#xff1a;数组的遍历&#xff1a; 案例…

基于DE2-115平台的VGA显示实验

一.任务需求 深入了解VGA协议&#xff0c;理解不同显示模式下的VGA控制时序参数&#xff08;行频、场频、水平/垂直同步时钟周期、显示后沿/前沿等概念和计算方式&#xff09;&#xff1b;通过Verilog编程&#xff0c;在至少2种显示模式下&#xff08;64048060Hz,102476875Hz&…

c++模板模式

文章目录 模板模式什么是模板模式为什么使用模板模式模板模式实现步骤 示例模板模式优缺点 模板模式 什么是模板模式 模板模式&#xff08;Template Method Pattern&#xff09;是一种行为设计模式&#xff0c;它定义了一个操作中的算法骨架&#xff0c;将某些步骤的具体实现延…

SEO之预估流量及价值(二)

初创企业搭建网站的朋友看1号文章&#xff1b;想学习云计算&#xff0c;怎么入门看2号文章谢谢支持&#xff1a; 1、我给不会敲代码又想搭建网站的人建议 2、新手上云 &#xff08;接上一篇。。。。&#xff09; 2、点击率 搜索结果页面各排名位置点击率也不精确。前面介绍的…

当游戏遭遇安全问题,我们应该怎么做?

在游戏安全领域&#xff0c;专业性最差、但最常见的案例类型是DDoS攻击&#xff08;分布式拒绝服务攻击&#xff09;。出于它的特性&#xff0c;中小厂商、独立开发者较容易遭受这类攻击。 例如&#xff0c;今年2月29日上线的手游《雷索纳斯》就遭受了名为ACCN组织发起的DDoS攻…

「Python-docx 专栏」docx 设置页面边距、页眉页脚高度

本文目录 前言一、docx 页面边距在哪里二、对 <w:pgMar> 的详细说明1、上边距的说明2、右边距的说明3、下边距的说明4、左边距的说明5、页眉高度的说明6、页脚高度的说明三、设置 docx 页边距、页眉页脚高度1、完整代码2、代码执行效果图四、补充一些内容1、页面边距的两…

曲线拟合 | 二次B样条拟合曲线

B 样条曲线拟合实例&#xff1a;能平滑化曲线 1. 实例1 为MASS包中mcycle数据集。它测试了一系列模拟的交通车事故中&#xff0c;头部的加速度&#xff0c;以此来评估头盔的性能。times为撞击时间(ms)&#xff0c;accel为加速度&#xff08;g&#xff09;。首先导入数据&#…

客观评价,可道云teamOS搭建的企业网盘,如Windows本地电脑一般的使用体验真的蛮不错

不管是企业网盘还是私有网盘&#xff0c;简单易用一直是我比较在意的。快速能上手使用&#xff0c;甚至不需要习惯一套新的操作逻辑&#xff0c;代表着不需要学习适应&#xff0c;能够迅速投入正常使用。 在这个过程中&#xff0c;可道云teamos以其Windows电脑般的流畅体验&am…

S级猫主食冻干测评出来了:希喂、K9、朗诺实测分享

对于许多宠物主人来说&#xff0c;一到挑选主食冻干就头疼。尽管主食冻干为猫咪带来的益处远超过普通猫粮&#xff0c;但其价格也相对较高。因此&#xff0c;许多宠物主人担心高价购买的主食冻干营养价值并不高。实际上&#xff0c;除了营养&#xff0c;安全性和配方也是选购时…