Java中的反射机制详解

news/2024/5/3 21:32:53

反射的简单demo

  1. 声明的原始类
    class Cat {private String name = "猫猫";public int age = 10;public Cat(){}public Cat(String name) {this.name = name;}public void hi() {System.out.println("hi~ " + name);}public void hi() {System.out.println(name + " cry");}
    }
    
  2. src目录下的配置文件re.properties
    classfullpath=com.zhl.Cat
    method=hi
    
  3. 编写反射代码
    public class Reflection01 {public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {// 加载配置文件中的信息Properties properties = new Properties();InputStream inputStream = ReflectionQuestion.class.getClassLoader().getResourceAsStream("re.properties");properties.load(inputStream);String classfullpath = properties.getProperty("classfullpath");String methodName = properties.getProperty("method");// 使用反射创建对象Class<?> aClass = Class.forName(classfullpath);Object o = aClass.newInstance();System.out.println(o.getClass());// 通过反射获取成员方法Method method = aClass.getMethod(methodName);method.invoke(o);// 通过反射获取成员变量(不能获取私有的)Field ageField = aClass.getField("age");System.out.println(ageField.get(o));// 通过反射获取构造器// 无参Constructor<?> constructor = aClass.getConstructor();System.out.println(constructor);// 有参Constructor<?> constructor2 = aClass.getConstructor(String.class);System.out.println(constructor2);}
    }
    

反射机制和传统调用方法的对比

public class Reflection02 {public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {m1();m2();}// 传统方法:直接创建对象public static void m1() {Cat cat = new Cat();long begin = System.currentTimeMillis();for (int i = 0; i < 1000000; i++) {cat.hi();}long end = System.currentTimeMillis();System.out.println("传统方案耗时:" + (end - begin) + "ms");}// 反射机制调用方法public static void m2() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class<?> aClass = Class.forName("com.zhl.Cat");// 无参构造Constructor<?> constructor = aClass.getConstructor();// 关闭访问检查的开关constructor.setAccessible(true);Object o = constructor.newInstance();Method method = aClass.getMethod("hi");method.setAccessible(true);long begin = System.currentTimeMillis();for (int i = 0; i < 1000000; i++) {method.invoke(o);}long end = System.currentTimeMillis();System.out.println("使用反射方案耗时:" + (end - begin) + "ms");}
}

反射的优点和缺点:

  • 优点:可以动态的创建和使用对象(也是框架底层核心),使用灵活。
  • 缺点:使用反射基本是解释执行,对执行速度有影响。

Class类

Class类的对象不是new出来的,是系统创建的,在类加载阶段生成的。
对于某个类的Class类对象,类只加载一次,在内存中只有一份。
每个类的实例都会记得自己是由哪个 Class 实例所生成。

  • 已知一个类的全类名 ,且该类在类路径下,可通过Class类的静态方法forName()获取
    • 应用场景:通过配置文件读取类的全路径,加载类
    String className;
    Class<?> clazz = Class.forName(className);
    
  • 若已知具体的类,通过 类的class获取,该方式最为安全可靠,程序性能最高
    • 应用场景:多用于参数传递,比如通过反射得到对应构造器对象
    Class<Cat> cat = Cat.class;
    
  • 已知某个类的实例,调用该实例的getClass()方法获取Class对象,实例:
    • 应用场景:通过创建好的对象,获取Class对象
    // 运行类型
    Class clazz = 对象.getClass();	
    
  • 其他方式
    获取类加载器,加载指定类 。
    ClassLoader loader =.class.getClassLoader();	
    Class<?> clazz = loader.loadClass("com.zhl.Cat");
    

类加载

  • 基本说明
    反射机制是 java实现动态语言的关键,也就是通过反射实现类动态加载

    1. 静态加载:编译时加载相关的类,如果没有则报错。
      依赖性太强
    2. 动态加载:运行时加载需要的类,如果运行时不用该类,则不报错。
      降低了依赖性
    3. 举例说明 (伪代码)
    String key = scan.next();
    switch(key) {case "1" : Dog dog = new Dog();dog.hi();break;case "2":Class<?> clazz = Class.forName("Person");Object o = clazz.newInstance();Method methodName = clazz.getMethod("hi");method.invoke(o);break;default:break;
    }
    

    注意这段代码中,并没有创建 DogPerson类(当前module中没有Dog或Person类),但是编译时,只会报 Dog 类没有创建,而Person类并没有监测出来是否被创建,只有真正被执行到这行代码时才会被加载,判断是否创建过Person类。

  • 类加载时机

    1. 当创建对象时(new)
    2. 当子类被加载时,父类也加载
    3. 调用类中的静态成员时
    4. 通过反射(动态加载)

    关于JVM的类加载可参考https://blog.csdn.net/m0_72406127/article/details/137058092?spm=1001.2014.3001.5501

通过反射获取类的结构信息

  • java.lang.Class

    1. getName:获取全类名
    2. getSimpleName:获取简单类名
    3. getFields:获取所有public修饰的属性,包含本类以及父类的
    4. getDeclaredFields:获取本类中所有属性
    5. getMethods:获取所有public修饰的方法,包含本类以及父类的
    6. getDeclaredMethods:获取本类中所有方法
    7. getConstructors:获取所有public修饰的构造器,包含本类
    8. getDeclaredConstructors:获取本类中所有构造器
    9. getPackage:以Package形式返回包信息
    10. getSuperClass:以Class形式返回父类信息
    11. getInterfaces:以Class[]形式返回接口信息
    12. getAnnotations:以Annotation[]形式返回注解信息
  • java.lang.reflect.Field

    1. getModifiers: 以int形式返回修饰符
      默认修饰符是0,public 是 1,private 是 2,protected 是 4,static 是 8 ,final是 16,多个不同的修饰符可以相加
    2. getType:以Class形式返回类型
    3. getName:返回属性名
  • java.lang.reflect.Method

    1. getModifiers:以int 形式返回修饰符
    2. getName:返回方法名
    3. getReturnType:以Class形式获取 返回类型
    4. getParameterTypes:以Class[]返回参数类型数组
  • java.lang.reflect.Constructor

    1. getModifiers: 以int形式返回修饰符
    2. getName:返回构造器名(全类名)
    3. getParameterTypes:以Class[]返回参数类型数组

通过反射创建对象

  • 方式一:调用类中的publi 修饰的无参构造器
  • 方式二:调用类中的指定构造器
  • Class类相关方法
    • newlnstance:调用类中的无参构造器,获取对应类的对象
    • getConstructor(Class…clazz):根据参数列表,获取对应的public构造器对象
    • getDeclaredConstructor(Class…clazz):根据参数列表,获取对应的所有构造器 对象
  • Constructor类相关方法
    • setAccessible: 设为true,可以访问private修饰的构造器
    • newinstance(Object…obj): 调用构造器

在构造器/方法/属性中使用 getDeclaredXxx方法可以获取本类中的所有构造器/方法/属性,
通过setAccessible()方法,设置参数为true,关闭访问检查的开关,就可以直接访问和修改被 private 修饰的构造器/方法/属性。


http://www.mrgr.cn/p/11873535

相关文章

HarmonyOS NEXT应用开发之深色跑马灯案例

介绍 本示例介绍了文本宽度过宽时,如何实现文本首尾相接循环滚动并显示在可视区,以及每循环滚动一次之后会停滞一段时间后再滚动。 效果图预览使用说明: 1.进入页面,检票口文本处,实现文本首尾相接循环滚动,且在同一可视区,滚动完成之后,停滞一段时间后继续滚动。 实现…

[面向对象] 单例模式与工厂模式

单例模式 是一种创建模式&#xff0c;保证一个类只有一个实例&#xff0c;且提供访问实例的全局节点。 工厂模式 面向对象其中的三大原则&#xff1a; 单一职责&#xff1a;一个类只有一个职责&#xff08;Game类负责什么时候创建英雄机&#xff0c;而不需要知道创建英雄机要…

【jinja2】模板渲染

HTML文件 return render_template(index.html)h1: 一级标题 变粗变大(狗头 <

性能测试——性能测试-linux监控工具——Jmeter插件之ServerAgent服务器性能监控工具的安装和使用

安装插件 1、在Jmeter官网:https://jmeter-plugins.org/wiki/PluginsManager/下载插件管理器Plugins-manager.jar参考博客地址:https://blog.csdn.net/qq_45664055/article/details/105979481需要先安装java,设置环境变量: 123

菜品分类,做这个公共字段填充我真破防了

第一个小节不属于业务功能开发,偏向技术的 公共字段:在业务表中有很多相同的字段,例如创建人,创建时间,修改人,修改时间,在维护数据时候,都需给这些字段赋值,这样程序之中出现很多重复的代码 使用切面统一处理 枚举:可以标识当前操作的类型(insert或update) AOP:切…

yolov8目标检测 部署瑞芯微rk3588记录

1. 前置条件 本地电脑系统&#xff0c;ubuntu20.04 训练代码&#xff1a; 训练代码下载的ultralytics官方代码 SHA&#xff1a;6a2fddfb46aea45dd26cb060157d22cf14cd8c64 训练代码仅做数据修改&#xff0c;类别修改&#xff0c;代码结构未做任何修改 需要准备的代码&#…

Oracle数据库 :查询表结构脚本

查询脚本 &#xff1a; SELECT CASE WHEN a.column_id1 THEN a.TABLE_NAME ELSE END AS 表名, a.column_id AS 序号, a.column_name as 列名, REPLACE(comments, CHR(10), ) as 列说明, a.data_type || ( || a.data_length || ) as 数据类型, a.DATA_LENGTH AS 长度, a.DATA_…

8thWall vs. AR.js

对于熟悉 JavaScript、WebGL 和 HTML5 等 Web 技术的数字创作者来说&#xff0c;8th Wall 提供了功能丰富且强大的 AR 开发平台&#xff0c;尽管价格较高。 然而&#xff0c;新手开发人员和专注于基于标记的 AR 的开发人员可能会发现 AR.js 更易于使用且更经济实惠。 1、8th Wa…

【单调栈】力扣85.最大矩形

好久没更新了 ~ 我又回来啦&#xff01; 两个好消息&#xff1a; 我考上研了&#xff0c;收到拟录取通知啦&#xff01;开放 留言功能 了&#xff0c;小伙伴对于内容有什么疑问可以在文章底部评论&#xff0c;看到之后会及时回复大家的&#xff01; 前面更新过的算法&#x…

重构国内游戏账号登录系统的思考和实践

本期作者 背景 账号登录系统&#xff0c;作为游戏发行平台最重要的应用之一&#xff0c;在当前的发行平台的应用架构中&#xff0c;主要承载的是用户的账号注册、登录、实名、防沉迷、隐私合规、风控等职责。合规作为企业经营的生命线&#xff0c;同时&#xff0c;账号登录作为…

在线编辑器 CodeMirror

如何优雅的在网页显示代码 如果开发在线编辑器 引入资源&#xff1a; <link rel"stylesheet" href"https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.60.0/codemirror.min.css"><script src"https://cdnjs.cloudflare.com/ajax/libs/c…

AI极速批量换脸!Roop-unleashed下载介绍,可直播

要说AI换脸领域,最开始火的项目就是Roop了,Roop-unleashed作为Roop的嫡系分支,不仅继承了前者的强大基因,更是在功能上实现了重大突破与升级 核心特性 1、可以进行高精度的图片、视频换脸,还能实时直播换脸,换脸效果真实、自然 2、不仅支持N卡处理程序(cuda),还额外提…

AI大模型日报#0416:李飞飞《2024年人工智能指数报告》、Sora加入Adobe、李彦宏聊百度大模型之路

​导读&#xff1a; 欢迎阅读《AI大模型日报》&#xff0c;内容基于Python爬虫和LLM自动生成。目前采用“文心一言”生成了每条资讯的摘要。标题: 刚刚&#xff0c;李飞飞团队发布《2024年人工智能指数报告》&#xff1a;10大趋势&#xff0c;揭示AI大模型的“喜”与“忧” 摘…

uni-app如何生成骨架屏

为什么需要骨架屏&#xff1a;为了缓解用户打开程序时等待接口的焦虑情绪 1.打开微信开发者工具&#xff0c;找到模拟器中的页面信息&#xff0c;选择生成骨架屏 2.将生成的wxml代码复制到vscode&#xff0c;在index的components中新建一个vue文件&#xff0c;只需保留请求接口…

使用Lagent AgentLego 搭建智能体

对于这个作业,这里只给出截图,不给详细过程,因为确实没有什么好写的。具体的步骤可以查看官方教程。 作业要求 基础作业完成 Lagent Web Demo 使用,并在作业中上传截图。文档可见 Lagent Web Demo 完成 AgentLego 直接使用部分,并在作业中上传截图。文档可见 直接使用 Age…

CentOS7 boa服务器的搭建和配置

环境是CentOS7&#xff0c;但方法不局限于此版系统&#xff0c;应该是通用的。 具体步骤如下&#xff1a; 1. 下载boa源码 下载地址: Boa Webserver 下载后&#xff0c;进入压缩包所在目录&#xff0c;进行解压&#xff1a; tar xzf boa-0.94.13.tar.gz 2. 安装需要的工具b…

RILIR 复现 一些 idea

伪代码:在 if done 的时候,在环境中已经跑了一个 trajectory 了,利用当前的 trajectory 和专家的 demo 求一下 reward(文章中用的是 optimal transport 的几种方法) 否则,就继续在 observation 的基础上利用 actor 学到的策略 sample 出 action,并用 list 记录下当前的 …

PolarDB MySQL 版 Serverless评测|一文带你体验什么是极致弹性|后续

PolarDB MySQL 版 Serverless评测|一文带你体验什么是极致弹性|后续 弹性压测三后续自动缩容全局一致性测试测评体验 在上一篇PolarDB MySQL 版 Serverless测评博文中&#xff1a;https://developer.aliyun.com/article/1385834 关于弹性压测三通过增加只读节点压测来观测到Ser…

【C语言】多字节字符、宽字符(涉及字符集和编码)

字符集、编码&#xff1a; 字符集&#xff1a;一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称&#xff0c;包括各国家文字、标点符号、图形符号、数字等。例如&#xff1a;ASCII、Unicode、GB2312、GBK、GB18030、BIG5(繁体中文) ... 编码方式&#xff1a;符号…

【React】Ant Design自定义主题风格及主题切换

Ant Design 的自定义主题&#xff0c;对于刚入手的时候感觉真是一脸蒙圈&#xff0c;那今天给它梳理倒腾下&#xff1b; 1、自定义主题要点 整体样式变化&#xff0c;主要两个部分&#xff1a; 1.1、Design Token https://ant.design/docs/react/customize-theme-cn#theme 官…