反射 Reflection

news2025/2/26 8:24:16

反射

反射的概念

  1. 反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息(比如成员变量,构造器,成员方法等等),并能操作对象的属性及方法。反射在设计模式和框架底层都会用到
  2. 加载完类之后,在堆中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象包含了类的完整结构信息。通过这个对象得到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,形象的称之为反射

image.png

反射机制

Java反射机制可以完成

  1. 在运行时判断任意一个对象所属的类
  2. 在运行时构造任意一个类的对象
  3. 在运行时得到任意一个类所具有的成员变量和方法
  4. 在运行时调用任意一个对象的成员变量和方法
  5. 生成动态代理

反射相关的主要类:

  1. java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象
  2. java.lang.reflect.Method: 代表类的方法
  3. java.lang.reflect.Field: 代表类的成员变量
  4. java.lang.reflect.Constructor: 代表类的构造方法

一般使用:对象.方法 反射使用:方法.对象
一般使用:对象.变量 反射使用:变量.对象

反射优点和缺点

**优点:**可以动态的创建和使用对象(也是框架底层核心),使用灵活,没有反射机制,框架技术就失去底层支撑。
**缺点:**使用反射基本是解释执行,对执行速度有影响,

反射调用优化-关闭访问检查

Method和Field、Constructor对象都有setAccessible()方法
setAccessible作用是启动和禁用访问安全检查的开关。(默认为false)

  • 参数值为true表示:反射的对象在使用时取消访问检查,提高反射的效率。
  • 参数值为false表示:反射的对象执行访问检查

Class类

  1. Class也是类,因此也继承Object类

image.png

  1. Class类对象不是new出来的,而是系统创建的
  2. 对于某个类的Class类对象,在内存中只有一份,因为类只加载一次(以hashcode区别)(使用synchronized同步)
  3. 每个类的实例都会记得自己是由哪个 Class 实例所生成
  4. 通过Class对象可以完整地得到一个类的完整结构,通过一系列API
  5. Class对象是存放在堆的
  6. 类的字节码二进制数据,是放在方法区的, 有的地方称为类的元数据(包括 方法代码变量名,方法名,访问权限等等)https://www.zhihu.com/question/38496907

Class类的常用方法:

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. getlnterfaces:以Class[]形式返回接口信息
  12. getAnnotations:以Annotation[] 形式返回注解信息

获取Class对象的几种方式

  1. 代码阶段:Class.forName()

前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException,
例:Class clazz = Class.forName( "java.lang.Cat”);
应用场景:多用于配置文件,读取类全路径,加载类

  1. Class类阶段:类.class

前提:若已知具体的类,通过类的class 获取,该方式最为安全可靠,程序性能最高
应用场景:多用于参数传递,比如通过反射得到对应构造器对象

  1. Runtime阶段:对象.getClass()

前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象,
例:Class clazz = object.qetClass();
应用场景:通过创建好的对象,获取Class对象

  1. 其他方式(类加载器):

ClassLoader classLoader = object.getClass().getClassLoader();
Class clazz = classLoader.loadClass("类的全类名");

  1. 基本数据(int, char,boolean,float,double,byte,long,short) 按如下方式得到Class类对象

Class clazz = 基本数据类型.class;

  1. 基本数据类型对应的包装类,可以通过.type 得到Class类对象

Class clazz = 包装类.TYPE;

以下类型有Class对象

  1. 外部类,成员内部类,静态内部类,局部内部类,匿名内部类
  2. interface:接口
  3. 数组
  4. enum:枚举
  5. annotation:注解
  6. 最本基本数据类型
  7. void

类加载

基本说明

反射机制是java实现动态语言的关键,也就是通过反射实现类动态加载。

  1. 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
  2. 动态加载:运行时加载需要的类,如果运行时不用该类,则不报错,降低了依赖性

类加载时机

  1. 创建类的实例:属于静态加载。当使用 new 关键字创建一个类的实例时,该类会被加载、连接和初始化,这是在编译期就确定需要加载的类。
  2. 访问类的静态变量:属于静态加载。当访问一个类的静态变量(static field)时,如果该类还没有加载,则会触发类的加载、连接和初始化,这也是在编译期就确定需要加载的类。
  3. 调用类的静态方法:属于静态加载。当调用一个类的静态方法时,如果该类还没有加载,则会触发类的加载、连接和初始化,同样是在编译期确定需要加载的类。
  4. 访问类的静态字段的值:属于静态加载。当访问一个类的静态字段的值(static final field)时,不会触发类的初始化,因为这些字段在编译期就会被赋值。
  5. 使用反射:属于动态加载。通过反射机制来创建类的实例、访问类的静态变量或调用类的静态方法时,是在程序运行时根据需要动态加载类。

类加载过程

image.png
类加载各阶段完成任务
image.png
前两个阶段在JVM中

加载阶段(Loading)

加载阶段是指查找并加载类的字节码文件(.class 文件),一般是通过类加载器(ClassLoader)来完成的。类加载器根据类的全限定名在类路径中查找对应的字节码文件,并将其加载到内存中。

链接阶段(Linking)-验证

验证确保被加载的类符合 Java 虚拟机规范,比如检查字节码的格式、语义等。
目的是为了确保 Class 文件的字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身的安全。
包括:文件格式验证(是否以魔数 oxçafebabe开头)、元数据验证、字节码验证和符号引用验证。
可以考虑使用 -Xverify:none 参数来关闭大部分的类验证措施,缩短虚拟机类加载的时间

链接阶段(Linking)-准备

JVM 会在该阶段对静态变量,分配内存并默认初始化(对应数据类型的默认初始值如 0、0L、null、false等)。这些变量所使用的内存都将在方法区中进行分配

链接阶段(Linking)-解析

虚拟机将常量池内的符号引用转换为直接引用,比如将类、方法、字段等的符号引用解析为实际内存地址

初始化(Initialization)

到初始化阶段,才真正开始执行类中定义的 Java 程序代码,此阶段是执行()方法的过程。
()方法是由编译器按语句在源文件中出现的顺序,依次自动收集类中的所有静态变量的赋值动作和静态代码块中的语句,并进行合并。类初始化是按需进行的,只有在首次主动使用类时才会触发。
虚拟机会保证一个类的()方法在多线程环境中被正确地加锁、同步,如果多个线程同时去初始化一个类,那么只会有一个线程去执行这个类的()方法,其他线程都需要阻塞等待,直到活动线程执行()方法完毕

通过反射获取类的结构

通过反射创建对象

  1. 方式一:调用类中的public修饰的无参构造器
  2. 方式二:调用类中的指定构造器
  3. Class类相关方法
    1. newlnstance:调用类中的无参构造器,获取对应类的对象
    2. getConstructor(Class…clazz):根据参数列表,获取对应的构造器对象
    3. getDecalaredConstructor(Class…clazz):根据参数列表,获取对应的构造器对象
  4. Constructor类相关方法
    1. setAccessible():参数使用true:暴破,使用反射可以访问私有(private)构造器/属性/方法
    2. newlnstance(Object…obj):调用构造器
package com.gg
class abc{
    puiblic String name ;
    abc(String name){
        this.name = name ;
    }
}
Class<?> clazz = Class.forName("com.gg.abc");
Object o = clazz.newInstance(); // 调用无参构造 o的运行对象类型为abc类

Constructor<?>  c = clazz.getDecalaredConstructor(String.class);//调用有参构造
Object o1 = c.newInstance("gggg"); // o1的运行对象类型为abc类

通过反射访问类中的成员

  1. 根据方法名和参数列表获取Method方法对象:Method m =clazz.getDeclaredMethod(方法名,XX.class);
  2. 获取对象:Object o = clazz.newInstance();
  3. 暴破:m.setAccessible(true);
  4. 访问:Object returnValue = m.invoke(o,实参列表); //o表示对象
  5. 注意:如果是静态方法,则invoke的参数o,可以写成null
  6. 如果方法有返回值,统一返回Object,但其运行类型依旧是方法中定义的返回类型
package com.gg
class abc{
    puiblic String name ;
    abc(String name){
        this.name = name ;
    }
    public void aabc(String name){
        System.out.println(name + " " + this.name);
    }
}
// 获取Class对象
Class<?> clazz = Class.forName("com.gg.abc");
//调用有参构造
Constructor<?>  c = clazz.getDecalaredConstructor(String.class);
// o1的运行对象类型为abc类
Object o1 = c.newInstance("gggg"); 
// 获取aabc方法对象
Method m = clazz.getDeclaredMethod("aabc",String.class);
// 反射调用aabc方法
Object res = m.invoke(o1,"aaaa");
// 输出 "aaaa gggg"

通过反射访问类中的属性

  1. 根据属性名获取Field对象Field f = clazz.getDeclaredField(属性名);
  2. 暴破:
    1. f.setAccessible(true); // f 是Field
  3. 访问
    1. f.set(o,值);// o表示对象
    2. f.get(o); //o表示对象
  4. 注意:如果是静态属性,则set和get中的参数o,可以写成null
package com.gg
class abc{
    puiblic String name ;
    abc(String name){
        this.name = name ;
    }
    public void aabc(String name){
        System.out.println(name + " " + this.name);
    }
}
// 获取Class对象
Class<?> clazz = Class.forName("com.gg.abc");
//调用有参构造
Constructor<?>  c = clazz.getDecalaredConstructor(String.class);
// o1的运行对象类型为abc类
Object o1 = c.newInstance("gggg"); //此时name="gggg"
// 获取name属性对象
Field f = clazz.getDeclaredField("name");
// 设置name属性的值
f.set(o1,"123");// 此时name="123"
// 获取并输出name属性值
System.out.println(f.get(o1));
// 输出 "123"

Field类常用方法

java.lang.reflect.Field

  1. getModifiers:以int形式返回修饰符、
    1. [说明:默认修饰符 是0, public 是1,private 是2,protected 是 4,static是8,final是16]
    2. public static = public(1) + static(8) = 1 + 8 = 9
  2. getType:以Class形式返回类型
  3. getName:返回属性名

Method类常用方法

java.lang.reflect.Method

  1. getModifiers:以int形式返回修饰符
    1. [说明:默认修饰符 是0, public 是1,private 是2,protected 是 4,static是8,final是16]
  2. getReturnType:以Class形式获取 返回类型
  3. getName:返回方法名
  4. getParameterTypes:以Class[ ]返回参数类型数组

Constructor类常用方法

java.lang.reflect.Constructor

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

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

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

相关文章

集合Python开发环境搭建

目录 PyCharm搭建Python环境_非虚拟环境 Pycharm的优点 Pycharm的缺点 Pycharm的下载 Pycharm环境配置 VSCode搭建Python环境_非虚拟环境 VSCode的优点 VSCode的缺点 VSCode的下载 VSCode环境配置 虚拟环境使用 虚拟环境介绍 虚拟环境安装 创建虚拟环境 切换虚拟…

使用 Vue CLI 创建一个 Vue2 项目

全局安装 Vue CLI 参考官网 Vue CLI&#xff0c;安装命令如下 npm install -g vue/cli 目前 Vue CLI 的最新版本为 v5.0.8 创建 Vue2 项目 在希望创建项目的目录下打开命令行&#xff0c;键入命令 vue create my-project 其中 my-project 更改为自己需要的项目名 随后&a…

R语言程序设计(零基础速通R语言语法和常见函数的使用)

目录 1.Rstudio中的一些快捷键 2.R对象的属性 3.R语言中常用的运算符​编辑 4.R的数据结构 向量 如何建立向量&#xff1f; 如何从向量里面提取元素&#xff1f; 矩阵 如何建立矩阵&#xff1f; 如何从矩阵里面提取元素&#xff1f; 数据框 如何建立数据框&#xf…

行业逆行者倪张根的十数年

在2015年的一场发布会上,梦百合家居董事长倪张根接受完全国80多家媒体的群访后,突然起身深深鞠了一躬,把在场的记者们吓了一跳。 对此,倪张根直接、坦率地承认“就是想讨好在座的各位”,这种不够柔和、不够世故的直球表达方式,在这个向来讲究中庸的社会,有种让人避之不及却又惊…

idea maven 项目融合

背景 &#xff1a;项目A 和项目B 是两个独立的多模块项目&#xff0c;项目A 和项目B &#xff0c;均为独立的数据源 。其中项目B 有两个数据原。 需要将项目B 以多模块的方式融合进项目A。 解决版本。建立项目C&#xff0c;只含有pom的&#xff0c;空项目&#xff0c;项目A和项…

【经验分享】Wubuntu------体验Windows和Ubuntu的结合体

【经验分享】Wubuntu------体验Windows和Ubuntu的结合体 最近看到有一款Wubuntu的文章&#xff0c;对于习惯使用windows操作系统&#xff0c;又不熟悉ubuntu系统的程序员小白来说&#xff0c;可以说是福音了。目前的Wubuntu兼容性可能还有一点问题&#xff0c;如果再迭代几次的…

nodejs 使用express插件multer文件上传,接收不到文件的bug

把路径改成绝对路径即可 改成 temp是你想上传到文件夹的路径&#xff0c;一般是在项目根目录下

pinia的使用vue3

1.安装pinia pinia持久化工具pinia-plugin-persist npm install pinia pinia-plugin-persist -D -S2.使用pinia main.js import store from "//store"; app.use(store);index.js import { createPinia } from "pinia"; import piniaPluginPersist fro…

攻防世界新手模式例题(Web)

PHP2 首先我们查看页面&#xff0c;查看前端代码 发现均没有什么有效信息&#xff0c;由题目可知&#xff0c;此问题与php相关&#xff0c;于是我们可以看一下他的index.php文件 查看时用?index.phps 补充知识&#xff1a;phps文件就是php的源代码文件&#xff0c;通常用于…

【超图】白模数据如何与抽屉效果结合,展示白膜内部结构

作者&#xff1a;taco 最近在支持的过程中&#xff0c;客户在看别的项目中&#xff0c;发现白模是可以抽插的。而非单独一个白色模型建筑。那么如何使用SuperMap产品来实现抽插的效果呢&#xff1f;本篇文章结合SuperMap iDesktopX产品以及SuperMap iClient for Cesium产品进行…

工业级5g路由器使用案例(5g智慧安防解决方案)

​项目背景: 现代化智慧安防需要满足远程可视化监控、设备联网管理、数据加密传输等多重需求,对通信网络的带宽、时延、安全性等提出了很高要求。业内急需一款高可靠、高性能、易管理的通信网关设备,来确保安防系统的顺利运行。 安装部署: SR800-D路由器采用紧凑型全金属机箱…

【Linux进阶之路】HTTPS = HTTP + S

文章目录 一、概念铺垫1.Session ID2.明文与密文3.公钥与私钥4.HTTPS结构 二、加密方式1. 对称加密2.非对称加密3.CA证书 总结尾序 一、概念铺垫 1.Session ID Session ID&#xff0c;即会话ID&#xff0c;用于标识客户端与服务端的唯一特定会话的标识符。会话&#xff0c;即客…

后端系统开发之——接口参数校验

今天难得双更&#xff0c;大家点个关注捧个场 原文地址&#xff1a;后端系统开发之——接口参数校验 - Pleasure的博客 下面是正文内容&#xff1a; 前言 在上一篇文章中提到了接口的开发&#xff0c;虽然是完成了&#xff0c;但还是缺少一些细节——传入参数的校验。 即用户…

TCP - 传输控制协议

TCP - 传输控制协议 是一种面向连接的可靠传输协议。 特点&#xff1a; TCP是面向连接&#xff08;虚连接&#xff09;的传输层协议。 每一条TCP连接有且只能有两个端点。 可靠、有序、无丢弃和不重复。 TCP协议提供全双工通讯。 发送缓存 存放发送方TCP准备发送的数据。T…

一键截取万像:视频快照工具的终极指南

在这个视频时代,我们不可能手动截取每一个视频的特定帧作为缩略图或参考用途。这不仅费时费力,而且效率低下。但是,有了Python和强大的库,您可以创建一个自动化工具,在几秒钟内从视频文件中获取缩略图快照。 在本文中,我将分享一个Python脚本,它使用wxPython和OpenCV库,让您只…

基于有限状态机开发健壮的Nodejs/TCP客户端

有限状态机是一种数学计算模型&#xff0c;它描述了在任何给定时间只能处于一种状态的系统的行为。形式上&#xff0c;有限状态机有五个部分&#xff1a; 初始状态值 (initial state)有限的一组状态 (states)有限的一组事件 (events)由事件驱动的一组状态转移关系 (transition…

Foxmail邮箱空间不够或邮件数太多

Foxmail邮箱空间不够或邮件数太多 解决办法&#xff1a; ①远程管理&#xff0c;删除远程邮件 ②删除本地邮件并同步服务器 ①远程管理&#xff0c;删除远程邮件 ②删除本地邮件并同步服务器 打开设置》》高级 此外&#xff0c;为了方便管理邮件可以设置过滤器 欢迎各位大佬…

51单片机LED8*8点阵显示坤坤跳舞打篮球画面

我们作为一名合格的 ikun&#xff0c;专业的小黑子&#xff0c;这个重要的知识必须学会。 先看效果&#xff1a; 51LED点阵_鸡你太美 这里我们首先要用到延时函数Delay&#xff1a; void Delay(unsigned int xms) {unsigned char i, j;while(xms--){ i 2;j 239;do{while (-…

物联网和工业物联网的区别——青创智通

工业物联网解决方案-工业IOT-青创智通 物联网&#xff08;IoT&#xff09;和工业物联网&#xff08;IIoT&#xff09;作为现代科技的重要分支&#xff0c;正在逐渐渗透到我们的日常生活和工业生产中。它们的应用范围广泛&#xff0c;涵盖了从智能家居到自动化工厂的多个领域。…

CTF题型 Http2降级走私原理分析例题分享

CTF题型 Http2降级走私原理分析&例题分享 文章目录 CTF题型 Http2降级走私原理分析&例题分享HTTP/2请求走私的产生回顾一下Http请求走私原理Http2请求的消息划分实际生产环境的限制如何利用H2.CL 实验环境准备例题分析H2.CL请求走私[GeekChanllenge 2023 Ez_Smuggling]…