Java反射 -- 详细介绍 (框架核心)

反射 是 Java框架 的核心 ,无论是Tomcat、SpringMVC、Spring IOC、Spring AOP、动态代理 ,都使用到了 反射

反射的作用简单讲就是 无需 new 对象,就可以动态获取到一个类的全部信息,包括 属性、方法,构造器,以及他们的修饰符、参数、注解 等等... 从而构造出 对象实例 并对 对象实例 进行操作

因此,学好反射是必须的,接下来就学习如何使用反射

这是我们下面要进行操作的类

public class Student {private String name;private int age;public String gender;public String address;public Student() {}public Student(String name, int age, String address) {this.name = name;this.age = age;this.address = address;}public Student(String name, int age, String gender, String address) {this.name = name;this.age = age;this.gender = gender;this.address = address;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getGender() {return gender;}public void setGender(String gender) {this.gender = gender;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}private void study(){System.out.println("学生在学习");}private void sleep(){System.out.println("学生在睡觉");}public String eat(String something){System.out.println("学生在吃" + something);return "学生已经吃完了,非常happy";}public String toString() {return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", address = " + address + "}";}
}

获取字节码文件对象(即 类对象)的三种方式

  • 通过 Class类 里面的 静态方法forName("全类名")(最常用)
  • 通过 类名.class 属性获取
  • 通过对象获取字节码文件对象 -- 对象名.getClass()

什么是字节码文件对象?

java文件:就是我们自己编写的java代码。

字节码文件:就是通过java文件编译之后的class文件(是在硬盘上真实存在的,用眼睛能看到的)

字节码文件对象:当class文件加载到内存之后,虚拟机自动创建出来的对象。这个对象里面就包含了类的所有信息。并且该对象在内存中是唯一的(存在于 JVM 的方法区中)

往后 获取类信息 的操作都是建立在 字节码文件对象 的基础上的

这三种获取 字节码文件对象 的方法是有区别的

  • Class.forName("全类名") -- 在 java文件阶段 就可以获取 字节码文件对象,因此这是最常用的
  • 类名.class -- 要在 类加载完成阶段 才能获取
  • 对象名.getClass) -- 要在 对象已经被创建出来的阶段 才能获取

代码示例

//第一种方法
Class clazz1 = Class.forName("com.zhuyuanjie.reflectdemo.Student");//第二种方法
Class clazz2 = Student.class;//第三种方法
Student s = new Student();
Class clazz3 = s.getClass();
System.out.println(clazz1 == clazz2);//true
System.out.println(clazz2 == clazz3);//true

获取 构造方法 并使用

不许通过 new ,我们也能通过反射获取到实例对象

大致步骤 -- 获取构造器对象,调用构造器的 newInstance 方法就可以创建出实例对象

——— 1.首先获取构造器对象 ————

方法如下:

方法名说明
Constructor<?>[] getConstructors()获得所有的构造(只能public修饰)
Constructor<?>[] getDeclaredConstructors()获得所有的构造(包含private修饰)
Constructor getConstructor(Class<?>... parameterTypes)获取指定构造(只能public修饰)
Constructor getDeclaredConstructor(Class<?>... parameterTypes)获取指定构造(包含private修饰)

观察上面表格发现,方法中如果没加 Declareed 就只能获取 public 的构造方法,而加了 Declareed 就可以获取全部,

而且方法末尾如果有 s 是获取所有,没加 s 是获取指定的构造器,需传入 指定构造器的参数列表

代码实例

        //获得class字节码文件对象Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");//获取构造方法对象//获取所有构造方法(public)Constructor[] constructors1 = clazz.getConstructors();for (Constructor constructor : constructors1) {System.out.println(constructor);}//获取指定的空参构造Constructor con1 = clazz.getConstructor();System.out.println(con1);//获取带参数的构造方法Constructor con2 = clazz.getDeclaredConstructor(String.class);System.out.println(con2);

——— 2 调用 newInstance 方法,创建 实例对象———

//1.获取整体的字节码文件对象
Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");
//2.获取空参的构造方法
Constructor con = clazz.getConstructor();
//3.利用空参构造方法创建对象
Student stu = (Student) con.newInstance();
System.out.println(stu);

上面代码中,如果我们获取到的构造方法是 private 属性,那么我们还不能直接调用,需要调用 setAccessible(true)方法 传入参数 true,来临时取消访问权限,如下:

Class clazz = Class.forName("com.zhuyuanjie.reflectdemo1.Student");Constructor con = clazz.getConstructor();//调用 setAccessible(true) 方法
con.setAccessible(true);Student stu = (Student) con.newInstance();
System.out.println(stu);

该方法不止用在构造方法上,包括接下来的 属性、方法 等,只要对 private修饰 的进行操作,就需要调用

获取 成员变量(属性) 并使用

方法名说明
Field[] getFields()返回所有成员变量对象的数组(只能拿public的)
Field[] getDeclaredFields()返回所有成员变量对象的数组,存在就能拿到
Field getField(String name)返回单个成员变量对象(只能拿public的)
Field getDeclaredField(String name)返回单个成员变量对象,存在就能拿到

可以发现以上方法名的结构,与 获取构造方法使用到的方法 一样,这里不在赘述

代码实例

//1.获取class对象Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");//获取成员变量的对象(public + private)Field[] fields2 = clazz.getDeclaredFields();for (Field field : fields2) {System.out.println(field);}System.out.println("===============================");//获得单个成员变量对象//如果获取的属性是不存在的,那么会报异常//Field field3 = clazz.getField("aaa");//System.out.println(field3);//NoSuchFieldExceptionSystem.out.println("===============================");//获取单个成员变量(私有)Field field5 = clazz.getDeclaredField("name");System.out.println(field5);

获取到 Field 对象后,我们就能得到 成员变量 的一切信息

//1.获取class对象Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");Field name = clazz.getDeclaredField("name");//临时取消访问权限name.setAccessible(true);//获取权限修饰符int modifiers = name.getModifiers(); //2//获取属性名String n = name.getName(); // name//获取数据类型Class<?> type = name.getType(); //class java.lang.String//等等... 还有很多,不在展示

还可以获取和修改 成员变量 的值

方法说明
void set(Object obj, Object value)赋值
Object get(Object obj)获取值
        Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");Field field = clazz.getDeclaredField("name");field.setAccessible(true);//设置(修改)name的值//参数一:表示要修改哪个对象的name?//参数二:表示要修改为多少?field.set(s,"张三");//获取name的值//表示我要获取这个对象的name的值String result = (String)field.get(s); // 张三

获取 成员方法 并运行

获取 成员方法 的方法和获取 成员的变量 的方法几乎一样,就是把 Field 改为 Method

而 获取到 成员方法 后,通过调用 Object invoke(Object obj, Object... args) 进行运行

其中

参数一:用obj对象调用该方法

参数二:调用方法的传递的参数(如果没有就不写)

        //1.获取字节码文件对象Class clazz = Class.forName("com.zhuyuanjie.reflectdemo.Student");//2.获取一个对象//需要用这个对象去调用方法Student s = new Student();//3.获取一个指定的方法//参数一:方法名//参数二:参数列表,如果没有可以不写Method eatMethod = clazz.getMethod("eat",String.class);//运行//参数一:表示方法的调用对象//参数二:方法在运行时需要的实际参数//注意点:如果方法有返回值,那么需要接收invoke的结果//如果方法没有返回值,则不需要接收String result = (String) eatMethod.invoke(s, "重庆小面");System.out.println(result);

同样的,如果方法是 private ,也需要调用 setAccessible(true) 方法

除了以上最常用的获取 构造方法 、成员变量 、成员方法 ,在框架中还经常通过反射获取 类 、 属性 、方法 上的注解信息

有需要可以看我的另外一篇博客,地址:

http://t.csdn.cn/qyDp0icon-default.png?t=N6B9http://t.csdn.cn/qyDp0

而且我的 Gitee 上有 Tomcat 、SpringMVC 等框架的核心源码仿写,可以感受下反射在框架中的使用,Gitee 地址如下:

朱元杰的Gitee -- 框架源码仿写https://gitee.com/Speed_Demon/projects

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

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

相关文章

边写代码边学习之全连接Dense

1. 全连接原理 全连接神经网络&#xff08;Fully Connected Neural Network&#xff09;是一种最基本的神经网络结构&#xff0c;也被称为多层感知器&#xff08;Multilayer Perceptron&#xff0c;MLP&#xff09;。其原理是模拟人脑神经元之间的连接方式&#xff0c;通过多个…

pytorch学习——多层感知机

一.感知机 感知机——神经网络基本单元&#xff0c;最简单的深度网络称为多层感知机。多层感知机由多层神经元组成&#xff0c;每一层与它上一层相连&#xff0c;从中接收输入&#xff0c; 同时每一层也与它的下一层相连&#xff0c;影响当前层的神经元。 解释&#xff1a;如果…

生态系统景观指数-聚集度指数AI计算

景观指数是景观生态学的常见指标&#xff0c;可用于不同生态系统的特征识别。景观指数是反映景观结构与空间格局的定量指标&#xff0c;目前已成为景观生态学领域常用的分析景观格局、度量空间异质性的重要方法。不同水平下的指数结果往往代表不同含义&#xff0c;应在把握指数…

决策树学习

决策树学习 决策树决策树基础适用决策树学习的经典目标问题样本的表示训练样本决策树的概念发展历史 经典决策树算法ID3算法属性选择和节点混杂度&#xff08;Impurity&#xff09;ID3 Q1: 哪个属性是最佳属性&#xff1f;当前最佳属性节点选择熵&#xff08;Entropy&#xff0…

如何高效实现文件传输:小文件采用零拷贝、大文件采用异步io+直接io

一般会如何实现文件传输&#xff1f; 服务器提供文件传输功能&#xff0c;需要将磁盘上的文件读取出来&#xff0c;通过网络协议发送到客户端。如果需要你自己编码实现这个文件传输功能&#xff0c;你会怎么实现呢&#xff1f; 通常&#xff0c;你会选择最直接的方法&#xf…

交叉编译----宿主机x86 ubuntu 64位-目标机ARMv8 aarch64

1.交叉编译是什么&#xff0c;为什么要交叉编译 编译&#xff1a;在一个平台上生成在该平台上的可执行代码交叉编译&#xff1a;在一个平台上生成在另一个平台上的可执行代码交叉编译的例子&#xff1a;如51单片机的可执行代码&#xff08;hex文件&#xff09;是在集成环境kei…

AT15透明屏有哪些特点?

AT15透明屏是一种新型的显示技术&#xff0c;它采用了透明材料制成的屏幕&#xff0c;可以实现透明显示效果。这种屏幕可以广泛应用于各种领域&#xff0c;如商业广告、展览展示、智能家居等。 AT15透明屏的特点之一是其高透明度。 由于采用了透明材料制成&#xff0c;AT15透明…

深度对话|Sui资产所有权如何让游戏体验更好

近日&#xff0c;我们采访了Mysten Labs的游戏产品总监Bill Allred&#xff0c;共同探讨了为什么Sui非常适合游戏。他分享了对Sui关键创新的看法&#xff0c;以及它为游戏开发者带来的价值&#xff0c;Sui的关键创新帮助开发者将他们所想象的游戏变为现实。 你能谈谈某些游戏的…

【微服务系统设计】系统设计基础:速率限制器

什么是速率限制器&#xff1f; 速率限制是指防止操作的频率超过定义的限制。在大型系统中&#xff0c;速率限制通常用于保护底层服务和资源。速率限制一般在分布式系统中作为一种防御机制&#xff0c;使共享资源能够保持可用性。 速率限制通过限制在给定时间段内可以到达您的 A…

vue解决跨域访问问题(个人学习笔记六)

目录 友情提醒第一章、跨越问题解决1.1&#xff09;什么是跨域问题&#xff1f;1.2&#xff09;第一种解决方式&#xff1a;后端设置允许跨域访问1.3&#xff09;第二种解决方式&#xff1a;前端配置代理 第二章、配置代理服务器2.1&#xff09;配置简单代理服务器2.2&#xff…

端口复用与重映射

端口复用和重映射 STM32F1有很多的内置外设&#xff0c;这些外设的外部引脚都是与GPIO复用的。也就是说&#xff0c;一个GPIO如果可以复用为内置外设的功能引脚&#xff0c;那么当这个GPIO作为内置外设使用的时候&#xff0c;就叫做复用。 大家都知道&#xff0c;MCU都有串口…

kotlin 编写一个简单的天气预报app(一)

使用Android Studio开发天气预报APP 今天我来分享一下如何使用Android Studio开发一个天气预报APP。在文中&#xff0c;我们将使用第三方接口获取实时天气数据&#xff0c;并显示在APP界面上。 步骤一&#xff1a;创建新项目 首先&#xff0c;打开Android Studio并创建一个新…

MySQL 中一条 SQL 的查询与更新

MySQL 中一条 SQL 的查询与更新 1 SQL 的查询1.1 MySQL 的逻辑架构图1.2 连接器1.3 查询缓存1.4 分析器1.5 优化器1.6 执行器 2 SQL 的更新2.1 redo log&#xff08;重做日志&#xff09;2.2 binlog&#xff08;归档日志&#xff09;2.3 redo log 和 binlog 日志的差异2.4 示例…

React 中 {} 的应用

列表渲染&#xff1a; 1.使用数组的 map 方法&#xff08;因为map 可以映射&#xff09; 2、列表要添加 key 属性&#xff0c;值要唯一 // 导入 // 用来获取 dom元素 import { createRoot } from "react-dom/client";// 内容 const contentArr [{ id: 1, name: &…

提高公文写作效率,可以采用模板和样例来辅助写作

采用模板和样例是提高公文写作效率的一种常见方法。 模板是指已经制作好的公文格式和结构模板&#xff0c;可以根据模板来组织和排版自己的文章&#xff0c;以减少排版时间和排版错误。常见的模板包括各类公文格式&#xff0c;例如通知、报告、请示等等。在使用模板的过程中&am…

GPT4ALL私有化部署 01 | Python环境

进入以下链接&#xff1a; https://www.python.org/downloads/release/python-3100/ 滑动到底部 选择你系统对应的版本&#xff0c;如果你是win&#xff0c;那么大概率是win-64bit 有可能你会因为网络的问题导致下载不了&#xff0c;我提供了 链接 接着只需要打开 等待…

Mac 快速生成树形项目结构目录

我这里使用的是通过包管理 Homebrew安装形式。没有安装的话可以自行搜索 Homebrew 安装方式 brew install tree直接到项目的根目录执行 tree 命令 tree 效果如下&#xff1a; or &#xff1a; tree -CfL 3效果如下&#xff1a;

opencv-24 图像几何变换03-仿射-cv2.warpAffine()

什么是仿射&#xff1f; 仿射变换是指图像可以通过一系列的几何变换来实现平移、旋转等多种操作。该变换能够 保持图像的平直性和平行性。平直性是指图像经过仿射变换后&#xff0c;直线仍然是直线&#xff1b;平行性是指 图像在完成仿射变换后&#xff0c;平行线仍然是平行线。…

SQL注入--题目

联合查询注入&#xff1a; bugku-这是一个神奇的登录框 手工注入&#xff1a; 点吧&#xff0c;输入0’发现还是&#xff1a; 输入0" 发现报错&#xff1a; 确定可以注入&#xff0c;判断字段有多少个 0"order by 1,2,3# 发现&#xff1a; 说明有两列。 输入 0&qu…