【详解】Java反射机制(打穿封装)

目录

定义:

用途:

反射基本信息:

反射相关的类(important):

Class类(反射机制的起源 )

Class类中的相关方法:

常用获得类相关的方法(重要)

常用获得类中属性相关的方法(重要)

获得类中注解相关的方法(了解)

获得类中构造器相关的方法(重要)

获得该类所有构造方法(重要)

反射示例:

获得Class对象的三种方式

反射的使用:

反射--创建对象

反射--调用私有的构造方法

反射--私有属性 

反射--私有方法

反射优点和缺点  

优点:

缺点: 

重点总结:

结语:


定义:

Java的反射(reflection)机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

用途:

(1)在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法 。

(2)反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无 论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的 就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类。

反射基本信息:

Java程序中许多对象在运行时会出现两种类型:运行时类型(RTTI)和编译时类型,例如Person p = new Student();这句代码中p在编译时类型为Person,运行时类型为Student。程序需要在运行时发现对象和类的真实信息。而通过使用反射程序就能判断出该对象和类属于哪些类。

反射相关的类(important):

类名用途
Class类代表类的实体,在运行的Java应用程序中表示类和接口
Field类代表类的成员变量/类的属性
Method类代表类的方法
Constructor类代表类的构造方法

Class类(反射机制的起源 )

代表类的实体,在运行的Java应用程序中表示类和接口. Class的官方文档:Class文档

Java文件被编译后,生成了.class文件,JVM此时就要去解读.class文件 ,被编译后的Java文件.class也被JVM解析为一个对象,这个对象就是 java.lang.Class .这样当程序在运行时,每个java文件就最终变成了Class类对象的一个实例。我们通过Java的反射机制应用到这个实例,就可以去获得甚至去添加改变这个类的属性和动作,使得这个类成为一个动态的类 .(如果觉得抽象没关系看下面演示后再看这个就明白了😎😎😎)

Class类中的相关方法:

常用获得类相关的方法(重要)

方法用途
getClassLoader()获得类的加载器
getDeclaredClasses()返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的)
forName(String className)根据类名返回类的对象
newInstance()创建类的实例
getName()获得类的完整路径名字

常用获得类中属性相关的方法(重要)

Field的官方文档:Field官方文档

方法用途
getField(String name)获得某个公有的属性对象
getFields()获得所有公有的属性对象
getDeclaredField(String name)获得某个属性对象
getDeclaredFields()获得所有属性对象

获得类中注解相关的方法(了解)

方法用途
getAnnotation(Class annotationClass)返回该类中与参数类型匹配的公有注解对象
getAnnotations()返回该类所有的公有注解对象
getDeclaredAnnotation(Class annotationClass)返回该类中与参数类型匹配的所有注解对象
getDeclaredAnnotations()返回该类所有的注解对象

获得类中构造器相关的方法(重要)

Constructor的官方文档:Constructor官方文档

方法用途
getConstructor(Class... parameterTypes)获得该类中与参数类型匹配的公有构造方法
getConstructors()获得该类的所有公有构造方法
getDeclaredConstructor(Class... parameterTypes)获得该类中与参数类型匹配的构造方法
getDeclaredConstructors()获得该类所有构造方法

获得该类所有构造方法(重要)

Method的官方文档:Method官方文档

方法用途
getMethod(String name, Class... parameterTypes)获得该类某个公有的方法
getMethods()获得该类所有公有的方法
getDeclaredMethod(String name, Class... parameterTypes)获得该类某个方法
getDeclaredMethods()获得该类所有方法

反射示例:

获得Class对象的三种方式

在反射之前,我们需要做的第一步就是先拿到当前需要反射的类的Class对象,然后通过Class对象的核心方法,达到反射的目的,即:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象, 都能够调用它的任意方法和属性,既然能拿到那么,我们就可以修改部分类型信息👍👍👍。

第一种:

使用类对象的 getClass() 方法

第二种:

使用 .class 方法。 说明:仅适合在编译前就已经明确要操作的Class

第三种:

使用 Class.forName("类的全路径名"); 静态方法。 前提:已明确类的全路径名。

注意这里是类的全路径,如果有包需要加包的路径例如(domo1.Student).

要声明异常。

其中第三种使用的最多如果大家要记得话就记下第三种。

class Student{public int age = 10;private String name = "gobeyye";
}
public class Main {public static void main(String[] args) {Student s1 = new Student();//第一种Class c1= s1.getClass();//第二种Class c2 = Student.class;//第三种Class c3 = null;try{c3 = Class.forName("Student");} catch (ClassNotFoundException e) {throw new RuntimeException(e);}System.out.println(c1 == c2);System.out.println(c1 == c3);System.out.println(c2 == c3);}
}

上面的代码运行结果如下:

都为true且在==的比较情况下,这说明:一个类在 JVM 中只会有一个 Class 实例。

反射的使用:

注意:所有和反射相关的包都在 import java.lang.reflect 包下面。

我们主要运用反射来进行创建类的实例和调用被private修饰的构造方法,方法和成员变量。

为了方便理解下面给出Student类的实现图片💕💕💕。

反射--创建对象

具体创建过程如下,这个不用记忆有用到的时候查资料知道怎么用即可。

下面有些方法是上面表格给出的如果不太了解的话可以向上翻。

public static void reflectNewInstance(){try{Class<?> classStudent = Class.forName("Student");Object objectStudent = classStudent.newInstance();Student student = (Student)objectStudent;System.out.println(student);} catch (ClassNotFoundException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}public static void main(String[] args) {reflectNewInstance();}

结果如下:可以发现我们成功通过反射创建了一个Student对象。 

不要怕抛了这么多异常,这个编译器有快捷键的不需要我们自己写。如下图我们把鼠标放到报错处等弹出如下界面是按下Alt + Shift + Enter键即可快速catch异常。

反射--调用私有的构造方法

具体过程如下:

和上面一样看着异常很多我们可以直接使用快捷键快速完成,不用记忆这个一般都是在项目里面才会用到,比赛不会有这些东西考试大概率也不会。

eclaredConstructorStudent.setAccessible(true);

这个代码在后续演示中会经常看到因为基本上用到private修饰的东西要用反射来调用的话都要把它设置为true这个方法可以查阅方法库双击shift即可查看。

至于

String.class,int.class

后面为什么要加.class这是语法规定

public static void reflectPrivateConstructor(){try{Class<?> classStudent = Class.forName("Student");Constructor<?> declaredConstructorStudent = classStudent.getDeclaredConstructor(String.class,int.class);declaredConstructorStudent.setAccessible(true);Object objectStudent = declaredConstructorStudent.newInstance("go",20);Student student = (Student)objectStudent;System.out.println(student);} catch (ClassNotFoundException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}public static void main(String[] args) {reflectPrivateConstructor();}

结果如下:上面这所以会打印Student(String,name)可以看看我前面给出的Student类的图,加上这个是为了证明private的带参数的构造方法被成功调用,显然可以被调用👍👍👍。

反射--私有属性 

改变被private修饰的成员变量的值。

后续在私有属性这里会经常调用到set方法,为了防止友友们疑惑这里声明这个set是人家自带的。

 具体演示如下:

classStudent.getDeclaredField("name");

传入要设置成员变量的标识符。

public static void reflectPrivateField(){try{Student student = new Student();Class<?> classStudent = Class.forName("Student");Field field = classStudent.getDeclaredField("name");field.setAccessible(true);field.set(student,"gobey");System.out.println(student);} catch (ClassNotFoundException e) {throw new RuntimeException(e);} catch (NoSuchFieldException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);}}public static void main(String[] args) {reflectPrivateField();}

结果如下:

可以发现在用println打印student时我们name成员变量的值成功被修改👌👌👌。

反射--私有方法

具体演示如下:

在这个方法中我们第一个参数传入的是我们要调用的方法名称,后面的参数是我们方法的参数,由于我们function方法只有一个String参数故我们传入一个String类型即可但是一定要记得后面要加一个.class后缀这是语法。 

invoke就是用来调用对应方法的。对应源码如下图:

代码如下: 

public static void reflectPrivateMethod(){try{Class<?> classStudent = Class.forName("Student");Method methodStudent = classStudent.getDeclaredMethod("function", String.class);methodStudent.setAccessible(true);Object objectStudent = classStudent.newInstance();Student student = (Student)objectStudent;methodStudent.invoke(student,"hehehehe");} catch (ClassNotFoundException e) {throw new RuntimeException(e);} catch (NoSuchMethodException e) {throw new RuntimeException(e);} catch (InstantiationException e) {throw new RuntimeException(e);} catch (IllegalAccessException e) {throw new RuntimeException(e);} catch (InvocationTargetException e) {throw new RuntimeException(e);}}public static void main(String[] args) {reflectPrivateMethod();}

 对应结果如下:可以看到被private修饰的方法成功被调用。

到这里我们反射常用的四个方式已经全部演示完毕,希望友友们自己可以试着实现一下,这个不是很难的👍👍👍。 

反射优点和缺点  

优点:

1. 对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法。

2. 增加程序的灵活性和扩展性,降低耦合性,提高自适应能力。

3. 反射已经运用在了很多流行框架如:Struts、Hibernate、Spring 等等。

缺点: 

1. 使用反射会有效率问题。会导致程序效率降低。

2. 反射技术绕过了源代码的技术,因而会带来维护问题。反射代码比相应的直接代码更复杂 。

重点总结:

1. 反射的意义。

2. 反射重要的几个类: Class类 、Field类、 Method类、 Constructor类。

3. 学会合理利用反射,一定要在安全环境下使用。

结语:

其实写博客不仅仅是为了教大家,同时这也有利于我巩固知识点,和做一个学习的总结,由于作者水平有限,对文章有任何问题还请指出,非常感谢。如果大家有所收获的话还请不要吝啬你们的点赞收藏和关注,这可以激励我写出更加优秀的文章。

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

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

相关文章

【十六】MySQL数据库设计篇

MySQL数据库设计篇 概述 做服务端开发离不开数据库设计&#xff0c;虽然说服务端技术一直在革新&#xff0c;但是MySQL一直都是我们首选使用的关系型数据库。服务端开发一直以来都是采用数据驱动研发的思想&#xff0c;可见数据库设计是非常重要的&#xff0c;数据库设计的好坏…

python--初学函数

函数&#xff08;function&#xff09;&#xff1a; 什么是函数&#xff1f; 具有名称的&#xff0c;是为了解决某一问题&#xff0c;功能代码的集合&#xff0c;叫做函数 python中函数如何定义&#xff1a;def>define function定义函数 def function_name([args临时变量…

docker推拉时的数据交换详解

前言 docker用了这么久了, 有没有想过, 在执行docker push 和 docker pull命令的时候, 数据是如何传递的呢? 换句话说, 如果要实现一个镜像仓库, 针对推拉的服务, 如何实现接口呢? 根据OCI 分发规范文档 的描述, 已经对整个推拉过程中要调用的接口有描述了. 但是, 纸上学来…

蓝桥集训之矩形牛棚

蓝桥集训之矩形牛棚 核心思想&#xff1a;单调队列 模板&#xff1a;Acwing.131.直方图矩形面积首先遍历所有下界 然后确定以该下界为底的直方图 求最大矩形 #include <iostream>#include <cstring>#include <algorithm>using namespace std;const int N 30…

前端基础篇-前端工程化 Vue 项目开发流程(环境准备、Element 组件库、Vue 路由、项目打包部署)

&#x1f525;博客主页&#xff1a; 【小扳_-CSDN博客】 ❤感谢大家点赞&#x1f44d;收藏⭐评论✍ 文章目录 1.0 环境准备 1.1 安装 NodeJs 1.2 验证 NodeJs 环境变量 1.3 配置 npm 的全局安装路径 1.4 切换 npm 的淘宝镜像( npm 使用国内淘宝镜像的方法(最新) ) 1.5 查看镜像…

win10-误删winsock恢复方法

文件链接放在最前面 链接&#xff1a;https://pan.baidu.com/s/1i9X0HJJOfo63fbtOETc1Xw?pwdlfqx 提取码&#xff1a;lfqx 误删后应该还是可以正常连接网络的&#xff0c;但是重启过后直接以太网和wifi都是无法使用的。下图是我后面网络正常补充的图片 误删后是只有飞行模式…

C语言操作符和数据类型的存储详解

CSDN成就一亿技术人 目录​​​​​​​ 一.操作符 一.算数操作符&#xff1a; 二.位移操作符&#xff1a; 三.位操作符&#xff1a; 四.赋值操作符&#xff1a; 五.单目操作符&#xff1a; 六.关系操作符&#xff1a; 七.逻辑操作符&#xff1a; 八.条件操作符&…

Xpath解析

目录 Xpath的简介&#xff1a; 简介&#xff1a; 相关概念&#xff1a; Xpath的使用&#xff1a; 安装&#xff1a; 用法&#xff1a; 第一步&#xff1a;准备html 第二步&#xff1a;将html构造出etree对象 第三步&#xff1a;使用etree对象的xpath()方法配合xpath表达…

Zookeeper(八)序列化与协议

目录 一 序列化与反序列化1.1 Jute序列化工具1.1 Recor接口1.2 OutputArchive和InputArchive 二 通信协议2.1 请求部分2.1.1 请求头2.2.2 请求体2.1.3 案例分析 2.2 响应部分2.2.1 响应头2.2.2 响应内容2.2.3 案例分析 官网&#xff1a;Apache ZooKeeper 一 序列化与反序列化 …

vector类详解及重要函数实现

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 今日主菜&#xff1a;vector类 主厨&#xff1a;邪王真眼 所属专栏&#xff1a;c专栏 主厨的主页&#xff1a;Chef‘s blog 坚持下去&#xff0c;成功不是目的&a…

CleanMyMac X 4.15.1 for Mac 最新中文破解版 系统优化垃圾清理工具

CleanMyMac X for Mac 是一款功能更加强大的系统优化清理工具&#xff0c;相比于 CleanMyMac 4.15.1来说&#xff0c;功能增加了不少&#xff0c;此版本为4.15.1官方最新中英文正式破解版本&#xff0c;永久使用&#xff0c;解决了打开软件崩溃问题&#xff0c;最新版4.15.1版本…

c++常考基础知识(2)

二.c关键字 关键字汇总 c中共有63个关键字&#xff0c;其中包括int&#xff0c;char&#xff0c;double等类型关键字&#xff0c;if&#xff0c;else&#xff0c;while&#xff0c;do&#xff0c;等语法关键字&#xff0c;还有sizeof等函数关键字。 三.数据结构 1.数组&#x…