反射复习(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.mzph.cn/bicheng/28913.shtml

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

相关文章

15.编写自动化测试(下)

标题 三、控制测试流程3.1 添加测试参数3.2 并行或连续运行测试3.3 显示函数输出3.4 指定/过滤测试用例名称3.5 忽略某些测试用例3.6 只运行被忽略的测试 四、测试的组织结构4.1 概念引入4.2 测试私有函数4.2 单元测试4.3 集成测试4.4 集成测试中的子模块4.5 二进制crate的集成…

Python脚本中使用 if 语句导致的错误代码

在 Python 脚本中使用 if 语句是一种常见的控制流程结构&#xff0c;用于根据条件决定程序的执行路径。当使用 Python 中的 if 语句时&#xff0c;可能会导致一些常见的错误。下面就是我经常遇到的错误代码示例及其可能的原因和解决方法&#xff0c;希望对大家有些帮助&#xf…

死锁预防之银行家算法

死锁预防之银行家算法 第一章 概述 Dijkstra提出了一种能够避免死锁的调度算法,称为银行家算法。 它的模型基于一个小城镇的银行家,他向一群客户分别承诺了一定的贷款额度,每个客户都有一个贷款额度,银行家知道不可能所有客户同时都需要最大贷款额,所以他只保留一定单位…

韩国职场新趋势:员工拒绝晋升,追求工作与生活的平衡

在当前职场环境中&#xff0c;晋升通常被视为职业生涯发展的重要里程碑。然而&#xff0c;据韩国《今日财经》报道&#xff0c;现代重工工会在今年的劳资谈判中提出了一个令人关注的要求——“拒绝晋升权”。这一要求反映了韩国职场的新趋势&#xff0c;即越来越多的员工对高薪…

长期保存红酒的挑战与应对策略

云仓酒庄雷盛红酒&#xff0c;以其卓着的品质和口感&#xff0c;赢得了无数葡萄酒爱好者的喜爱。然而&#xff0c;对于那些希望长期保存这些珍贵佳酿的人来说&#xff0c;如何确保红酒的品质和风味不受时间的影响&#xff0c;却是一项充满挑战的任务。 长期保存红酒的大挑战来自…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 火星字符串(100分) - 三语言AC题解(Python/Java/Cpp)

&#x1f36d; 大家好这里是清隆学长 &#xff0c;一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 &#x1f4bb; ACM银牌&#x1f948;| 多次AK大厂笔试 &#xff5c; 编程一对一辅导 &#x1f44f; 感谢大家的订阅➕ 和 喜欢&#x1f497; &#x1f…

电影《加菲猫家族》观后感

上周看了电影《加菲猫家族》&#xff0c;本片其中有很多明亮的画面&#xff0c;相关艳丽的色彩&#xff0c;充满温馨的场景&#xff0c;很符合加菲猫的一贯画风&#xff0c;即使反派出场时&#xff0c;带有阴暗的感觉&#xff0c;看起也不是特别吓人&#xff0c;比较欢乐气氛&a…

定时器介绍之8253芯片

目录 定时器简介 8253功能介绍 组成 工作原理 相关引脚 启动方法 计数方式 实现 读取计数值 定时器简介 8253功能介绍 内部结构 相关引脚 计数器组成 工作原理 启动方法 计数方式 初始化&#xff1a;写入控制字——>写入计数初值 实现 计数长度选择&#xff1a…

虚拟机Ping不通主机

1.问题描述 虚拟机IP&#xff1a; 192.168.3.133 主机ip&#xff1a;192.168.3.137 虚拟机Ping不通主机 主机可以ping通虚拟机 2.解决方案 设置桥接模式 控制面板找到网络和Internet设置 3.问题解决

geoserver 如何设置数据目录

在GeoServer中&#xff0c;数据目录是存储配置文件、数据存储、图层、样式等的重要目录。默认情况下&#xff0c;GeoServer的数据目录位于GeoServer安装目录下的data_dir文件夹。但在很多情况下&#xff0c;用户可能希望将数据目录设置在一个自定义位置&#xff0c;以便更好地管…

手持气象仪:科技与自然交汇的奇妙工具

TH-SQ5在广袤无垠的大自然中&#xff0c;天气总是瞬息万变&#xff0c;让人难以捉摸。然而&#xff0c;随着科技的进步&#xff0c;人类已经能够借助各种先进的仪器来预测和监测天气变化&#xff0c;其中&#xff0c;手持气象仪便是其中的佼佼者。 手持气象仪&#xff0c;顾名…

Java获取本机IP地址的方法(内网、公网)

起因是公司一个springboot项目启动类打印了本机IP地址加端口号&#xff0c;方便访问项目页面&#xff0c;但是发现打印出来的不是“无线局域网”的ip而是“以太网适配器”ip&#xff0c;如下图所示 这样就导致后续本地起项目连接xxl-job注册节点的时候因为不在同个局域网下ping…

打假-代码都让AI写,CS还有前途吗?加州大学伯克利分校:CDSS申请人数飙升48%!

一、背景 现在 CSDN 上发现了一篇文章 点进去文档的内容在说CDSS专业 还有一篇文章 文章基本上都是同一个意思&#xff0c;CDSS专业申请人数飙升 48%&#xff0c;但却有人刻意的把计算机专业突出出来。我不确定有人刻意把 CDSS 专业 和 CS 专业混淆的目的是什么&#xff1f;…

【数据结构】红黑树实现详解

在本篇博客中&#xff0c;作者将会带领你使用C来实现一棵红黑树&#xff0c;此红黑树的实现是基于二叉搜索树和AVLTree一块来讲的&#xff0c;所以在看本篇博客之前&#xff0c;你可以先看看下面这两篇博客 【C】二叉搜索树-CSDN博客 【数据结构】AVLTree实现详解-CSDN博客 在这…

设计四大基本原则的全面解析

每每问起设计四大基本原则&#xff0c;无论是蜚荣全球的业内大咖还是初出茅庐的张三李四&#xff0c;都会不约而同地告诉你一个答案&#xff1a;亲密性、对齐、重复、对比。 自罗宾威廉姆斯于《写给大家看的设计书》中提出后&#xff0c;四大基本原则涵盖了品牌、电商、包装、…

xxe漏洞学习

一、什么是xxe漏洞 XXE就是XML外部实体注入&#xff0c;当允许引用外部实体时&#xff0c; XML数据在传输中有可能会被不法分子被修改&#xff0c;如果服务器执行被恶意插入的代码&#xff0c;就可以实现攻击的目的攻击者可以通过构造恶意内容&#xff0c;就可能导致任意文件读…

数据驱动制造:EMQX ECP 指标监测功能增强生产透明度

迈向未来的工业生产&#xff0c;需要的不仅是自动化&#xff0c;更是智能化。如果工业企业的管理者能够实时监测每一生产环节的设备运行状态&#xff0c;每一数据点位情况&#xff0c;洞察和优化每一步生产流程&#xff0c;他们将能够做出更精准的决策&#xff0c;提高生产效率…

硕士毕业论文《基于磁纹理的磁化动力学研究》

前言 本文是博主的硕士毕业论文&#xff0c;应该也是“自旋电子学&#xff08;微磁学&#xff09;”博客专栏的最后一篇博客&#xff0c;该毕业论文预设排版的PDF版本见下载链接&#xff1a;https://download.csdn.net/download/qq_43572058/89447526。若该博客专栏对读者您的…

SD-WAN在教育行业的应用及优势解析

随着教育领域的数字化转型&#xff0c;网络技术的需求变得愈发迫切。作为一种前沿的网络解决方案&#xff0c;SD-WAN正在为教育行业提供强有力的支持。本文将详细探讨SD-WAN在教育行业的应用&#xff0c;并分析其为教育行业带来的众多优势。 实现多校区高效互联 教育机构通常拥…

Dart 弱引用进阶

前言 村里的老人说&#xff1a;“真正的强者&#xff0c;都是扮猪吃老虎。” 日常开发中经常需要用到弱引用&#xff0c;Dart 语言里也有提供弱引用的接口 WeakReference&#xff0c;我们可以基于它开发更强大的复杂结构。 在前面的文章中&#xff0c;我们用到了一个以弱引用…