当前位置: 首页 > news >正文

java反射(详细教程)

我们平常创建类的实例并调用类中成员需要建立在一个前提下,就是已经知道类名和类中成员的信息,灵活性大大降低。甚至在一些项目中还需要修改源码来满足使用条件,大大降低了操作的灵活性。

Java 反射(Reflection)是 Java 语言的一个重要特性,它允许程序在运行时而不是编译时获取类中成员,并且可以动态地操作这些类的成员。

在讲反射之前,我们先聊一聊反射机制中必不可少的一环:配置文件。我需要提前将我的类名,成员名填写到配置文件中去。这样在调用时就可以直接读取配置文件中的信息。相较于读取普通文件,配置文件的读取和调用更加简单。

一、读取配置文件:

1.创建配置文件:在指定的路径下(通常我放在src目录下,不为别的,就因为路径名简单)创建一个以“.properties”为结尾的File文件(普通的键值对形式)作为配置文件。

2.填写配置文件内容:以“键=值”的形式填写,不必添加空格和引号,调用时通过键的字符串形式调用(后面会举例说明)。

3.创建配置文件对象:首先new一个配置文件的对象,使用load方法将配置文件中的内容读取到配置文件对象中。

load方法提供了两种重载,既可以通过字节流输入,也可以通过字符流输入。推荐使用字节流输入,配置文件通常为全英文形式,字节流输入效率高。

4.获取配置文件中的内容:Properties类提供了一种getProperty(键)方法来获取配置文件中的信息,需要在方法中写入一个键,就会返回一个String类型键对应的值。这个String类型的值就是我们要从配置文件中拿到的值。

Exam我提前在src目录下创建了一个名为“p.properties”的配置文件并提前写好键值对来表示需要需要反射文件的路径、属性和方法。路径表示com.reflectNewEdu包下的名为“reflectEdu”的文件,我需要反射这个文件中的成员。

//配置文件的内容
//路径
className = com.reflectNewEdu.reflectEdu
//属性
ObjName = str
//方法
methodName = printContent
methodName1 = printSome

Exam在reflectEdu文件中需要写一些成员来帮助我们进行实验。

public class reflectEdu {//分别一个public和一个private属性public int num = 123;private String str = "字符串";//方法public void printContent() {System.out.println("输出内容");}private void printSome() {System.out.println("输出一些东西");}
}

Exam创建一个Test类,在Test类中填写main方法具体实现反射:

二、获取类对象(main函数中):

1.首先按照上面的步骤创建配置文件对象,并使用字节流加载配置文件进配置文件对象中。

Properties properties = new Properties();
properties.load(new FileReader("src/p.properties"));

2.为了绕过对象阶段创建类对象,Class.forName(类全名)提供了一种在硬盘阶段获取类中成员的方法。Class.forName(类全名)  的核心作用,是通过类的全限定名,让JVM加载这个类,并返回一个代表该类“模板”的 Class  对象。此时仅完成了“类的加载”,并没有创建任何属于这个类的具体对象,就像拿到了一张“汽车设计图纸”,但还没造出真正能开的汽车。

该方法需要写入一个String类型的类全名,我们通过getProperty(键)方法从配置文件中拿到这个类全名。

Class.forName()方法返回一个Class类型的对象,这是一个类对象。类对象并不是哪个类的实例,但可以通过这个类对象下的方法获取到类中的成员,甚至是获取类的实例。(还是挺抽象的

Class class0 = Class.forName(properties.getProperty("className"));

三、获取类对象中的成员:

一、属性(返回Field类型,需要import java.lang.reflect.Field;):

        1.获取当前类里所有属性:getDeclaredFields(); (返回数组)

        2.通过属性名获取属性:getDeclaredField(属性名);

        3.获取所有公共类型属性:getFields();(返回数组)

        4.获取公共类型中指定的属性:getField(属性名);

        5.设置对象的属性:属性对象.set(对象名,属性值)

        当属性被private修饰无法被调用时,可以使用:类对象名.setAccessible(true); 来进行暴力反射。

二、方法(返回Method类型,需要import java.lang.reflect.Method;):

        1.获取类里所有方法:getDeclaredMethods();(返回数组)

        2.通过方法名获取方法:getDeclaredMethod(方法名);

        3.获取所有公共类型方法:getMethods();(返回数组)

        4.获取公共类型中指定的方法:getMethod(方法名);

        5.运行指定的方法:方法对象.invoke(对象名, 参数); 

        第一个为对象名,第二个为参数名,如果没有参数可以不用输入,允许暴力反射。

三、构造方法(返回Constructor类型,需要import java.lang.reflect.Constructor;):

        1.获取类里所有构造方法:getDeclaredConstructors();(返回数组)

        2.获取指定的无参构造方法:getDeclaredConstructor();

        3.获取指定的带有参数的构造方法(举例:带有String和int类型的两个参数的构造方法):getDeclaredConstructor(String.class,int.class);

        4.获取所有公共类型的构造方法:getConstructors();(返回数组)

        5.获取公共类型中指定的一个方法(有参或无参):getConstructor();

        6.执行无参构造方法:Object 新变量名 = 构造方法对象/类对象名.newInstance(); 相当于Object obj = new (); 

        7.执行有参的构造方法:Object 新变量名 = 构造方法对象.newInstance(参数);

需要注意我标蓝的地方,都需要传入一个类对象,那么如何获取类的实例对象呢?

四、获取类的实例对象:

1.通过构造方法获取:我们已经拿到指向我们需要反射的类的对象了,直接通过getDeclaredConstructor()方法获取一个构造方法(我这里是无参的),再执行构造方法中的newInstance()方法不就行了嘛。

代码:

Constructor con = class0.getConstructor();
Object object = con.newInstance();

注:我们提前无法预测给类起的名字是什么,所以需要用它们共同的父类Object对象来接受。

2.通过类对象获取:对类对象直接使用newInstance()方法,这样无需知道类名,就可以创建类的实例对象啦。

Object object = class0.newInstance();

有了类的实例对象,我们就可以使用上面标蓝的方法了,比如调用类中的方法等。

由此,反射的整个过程就实现完了如果有什么地方不明白的话,可以私信讨论( o >o)/。


文章转载自:

http://aEqmrmEN.ykswq.cn
http://PI07vIQ8.ykswq.cn
http://sDzGOa7s.ykswq.cn
http://AVxMkWRS.ykswq.cn
http://Sxr35rVy.ykswq.cn
http://ewu9zAjV.ykswq.cn
http://lR7PGiwS.ykswq.cn
http://xIRVi3JR.ykswq.cn
http://h0pkDpt5.ykswq.cn
http://GesT4Ozr.ykswq.cn
http://mB4QV0uH.ykswq.cn
http://HWS4HDFT.ykswq.cn
http://jzO7M7ZP.ykswq.cn
http://Y5mEF8Dj.ykswq.cn
http://0thEFT3K.ykswq.cn
http://Km8sXagl.ykswq.cn
http://HfsJLsuE.ykswq.cn
http://L7NwYvBZ.ykswq.cn
http://LyYmyPGb.ykswq.cn
http://OlZuyE7W.ykswq.cn
http://9N08Jyl5.ykswq.cn
http://HDLr2rFH.ykswq.cn
http://I57GmzFa.ykswq.cn
http://MNHXIE1R.ykswq.cn
http://vYVJHAFS.ykswq.cn
http://trTFsnYE.ykswq.cn
http://03RuIISM.ykswq.cn
http://utY8vhRH.ykswq.cn
http://Bvi4wOPl.ykswq.cn
http://N4J8juJT.ykswq.cn
http://www.dtcms.com/a/379243.html

相关文章:

  • 【Leetcode】高频SQL基础题--1327.查找拥有有效邮箱的用户
  • Redis(集群)
  • 吾爱小工具!一键屏蔽流氓软件!
  • 告别网络监控“盲区”!OpManager全新升级解锁轻量监控新纪元!
  • 实验室试管架 | 塑料、金属等多种材质与规格 | 支持多种试管尺寸 | Sigma-Aldrich
  • .net 类库生成的DLL源码混淆加密
  • 北京-测试-入职金融公司第四周-加班&未发现bug
  • Story2Board: A Training-Free Approach for Expressive Storyboard Generation论文
  • 纯`css`轻松防止滚动穿透
  • 30天Java速成计划:从零基础到能刷算法题!
  • 【点云分类】简述对pointnet和pointnet++的理解
  • 【202509新版】Hexo + GitHub Pages 免费部署个人博客|保姆级教程
  • PigX整合knife4j
  • 安全审计-Ubuntu防火墙ufw
  • 编译器的相关知识(入门时著)
  • 开始 ComfyUI 的 AI 绘图之旅-Flux.1 ControlNet (十)
  • 企业微信内部应用js-sdk使用流程
  • Java Spring Boot常见异常全解析:原因、危害、处理与防范
  • Qt加载百度地图详细流程(附带报错解决方法)
  • 3D渲染时GPU内存不足解决措施
  • MySQL什么操作会加锁?
  • 中州养老:华为云设备管理接口开发全流程
  • 探讨图片以Base64存数据库的合理性
  • MoonBit 再次走进清华:张宏波受邀参加「思源计划」与「程序设计训练课」
  • RabbitMQ如何实现消息的持久化?
  • Crawlergo安装全流程
  • 完全背包问题 - 动态规划最优解法(Java实现)
  • 如何选择合适的双轴倾角传感器厂家提升水平监测准确性?
  • 洛谷PP5318 查找文献 (深度搜索与广度搜索)详解
  • 手机云服务是什么意思?