反射 Reflection

反射

反射的概念

  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.mzph.cn/news/757187.shtml

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

相关文章

Flutter 在 Windows 下的开发环境搭建(Flutter SDK 3.19.2)【图文详细教程】

Git 下载与安装 对于 Flutter 3.19&#xff0c;Git 版本需要 2.27 及以上 Git 下载&#xff1a; Git 官网&#xff1a;https://git-scm.com/Git 下载淘宝镜像&#xff1a;https://registry.npmmirror.com/binary.html?pathgit-for-windows/ 对于 Git 的安装教程&#xff0c;…

Python分析无人驾驶汽车在桂林市文旅行业推广的问卷

【项目背景】 通过市场调研、文本分析、访谈和问卷调查等方法&#xff0c;探讨&#xff1a; 网民对无人驾驶汽车出行服务的态度。无人驾驶安全员的行业背景。不同人群在旅游时的交通选择偏好。游客及当地居民对桂林市文旅路线的交通满意度。乘客对无人驾驶汽车的满意度。桂林…

超快速排序(蓝桥杯,归并排序,acwing)

题目描述&#xff1a; 在这个问题中&#xff0c;您必须分析特定的排序算法----超快速排序。 该算法通过交换两个相邻的序列元素来处理 n 个不同整数的序列&#xff0c;直到序列按升序排序。 对于输入序列 9 1 0 5 4&#xff0c;超快速排序生成输出 0 1 4 5 9。 您的任务是确…

Selenium不同版本配置自动下载驱动及打包细节

Selenium配置浏览器驱动 自动下载浏览器驱动的方法 selenium4.7.0自动下载浏览器驱动的方法 selenium4.11.0 或4.11.1手动设置浏览器驱动路径的方法pyinstaller打包程序时同时打包ChromeDriverchromedriver路径需要sys._MEIPASS的路径进行引用方法一&#xff1a;通过–add-data…

【Linux】从零开始认识进程 — 前篇

我从来不相信什么懒洋洋的自由。我向往的自由是通过勤奋和努力实现的更广阔的人生。。——山本耀司 从零开始认识进程 1 认识冯诺依曼体系2 操作系统3 进程3.1 什么是进程&#xff1f;&#xff1f;&#xff1f;3.2 进程管理PCB 3.3 Linux中的进程深入理解 3.4 进程创建总结 送给…

jvm的垃圾回收器以及触发full gc的场景

JVM&#xff08;Java虚拟机&#xff09;的垃圾回收器有很多种&#xff0c;主要包括以下几种&#xff1a; Serial收集器&#xff1a;串行收集器是最古老、最稳定的收集器。它使用单个线程进行垃圾收集工作&#xff0c;在进行垃圾回收时会暂停所有用户线程。 ParNew收集器&#…

Nebula Graph-01-Nebula Graph简介和安装以及客户端连接

前言 NoSQL 数据库 图数据库并不是可以克服关系型数据库缺点的唯一替代方案。现在市面上还有很多非关系型数据库的产品&#xff0c;这些产品都可以叫做 NoSQL。NoSQL 一词最早于上世纪 90 年代末提出&#xff0c;可以解释为“非 SQL” 或“不仅是 SQL”&#xff0c;具体解释要…

查找众数及中位数 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 众数是指一组数据中出现次数量多的那个数&#xff0c;众数可以是多个。 中位数只是指把一组数据从小到大排列&#xff0c;最中间的那个数&#xff0c;如果这组数…

整蛊小教程|让朋友手足无措的电脑自动关机

前言 这几天讲到shutdown关机命令&#xff0c;于是就出现了整蛊类的电脑教程。 这个故事我记得很清楚&#xff1a;在2012年的春天……当时的小白对电脑还不是很熟悉。某一天跟着朋友去网吧上网&#xff0c;这时候突然有个朋友发来一个.bat的文件&#xff0c;说双击打开有惊喜…

集合深入------理解底层。

集合的使用 前提&#xff1a;栈、堆、二叉树、hashcode、toString()、quesalus()的知识深入和底层理解。 1、什么是集合 集合就是咋们所说的容器 ​ 前面我们学习过数组 数组也是容器 ​ 容器&#xff1a;装东西的 生活中有多少的容器呀? 水杯 教室 酒瓶 水库 只要是…

Modbus TCP转Profinet网关如何实现Modbus主站与多设备通讯

在工业控制领域中&#xff0c;Modbus TCP转Profinet网关&#xff08;XD-ETHPN20&#xff09;扮演着连接不同设备间通讯的重要角色。当将Modbus主站与十几台服务器进行通讯时&#xff0c;通过modbus tcp转profinet网关&#xff08;XD-ETHPN20&#xff09;设备将不同协议间的数据…

关于OceanBase中旁路导入的应用分享

背景 前段时间&#xff0c;在用户现场协助进行OceanBase的性能测试时&#xff0c;我注意到用户常常需要运用 insert into select 将上亿行的数据插入到一张大宽表里&#xff0c;这样的批量数据插入操作每次都需要耗时半个小时左右。对这一情况&#xff0c;我提议用户尝试采用旁…

Class Re-Activation Maps for Weakly-Supervised Semantic Segmentation

摘要&#xff1a; 提取类激活映射(CAM)可以说是为弱监督语义分割(WSSS)生成伪掩码的最标准步骤。然而&#xff0c;我们发现伪掩码不理想的关键是在CAM中广泛使用的二进制交叉熵损失(BCE)。具体来说&#xff0c;由于BCE的池化方式是对类别求和&#xff0c;CAM中的每个像素可能对…

Linux课程____进程管理

记录工作日志 script 240319.log CTRLd 退出 cat 240319.log //查看 一、查看进程 1.静态 ps -aux ps -elf 2.动态 top 3.pgrep 查看特定条件的进程 pgrep -l “log” pgrep -l "ssh" pgrep -l -U redhat 4.pstree 查看进程树 pstree -aup 所有…

【Linux更新驱动、cuda和cuda toolkit】

目录 1. 更新显卡驱动1.1. 查看当前显卡驱动版本1.2. 删除原始显卡驱动1.3. 删除CUDA Toolkit1.4. 在NVIDIA官网找到2080Ti对应的最新驱动程序 2. 更新CUDA Toolkit2.1. 下载CUDA Toolkit2.2. 安装.run2.3. 添加环境变量2.4. 检查是否安装好了 最近需要更新服务器的显卡驱动和C…

目标检测——PP-YOLOv2算法解读

PP-YOLO系列&#xff0c;均是基于百度自研PaddlePaddle深度学习框架发布的算法&#xff0c;2020年基于YOLOv3改进发布PP-YOLO&#xff0c;2021年发布PP-YOLOv2和移动端检测算法PP-PicoDet&#xff0c;2022年发布PP-YOLOE和PP-YOLOE-R。由于均是一个系列&#xff0c;所以放一起解…

Fork - 将 GitHub 的某个特定仓库复制到自己的账户下

Fork - 将 GitHub 的某个特定仓库复制到自己的账户下 1. ForeverStrongCheng/OpenCV-tutorials2. Fork -> ForeverStrongCheng/R2CNN_Faster-RCNN_TensorflowReferences 访问仓库页面&#xff0c;点击 Fork 按钮创建自己的仓库。 Fork 是将 GitHub 的某个特定仓库复制到自己…

BetterDisplay Pro for Mac(显示器校准软件) v2.0.11激活版

BetterDisplay Pro是一款由waydabber开发的Mac平台上的显示器校准软件&#xff0c;可以帮助用户调整显示器的颜色和亮度&#xff0c;以获得更加真实、清晰和舒适的视觉体验。 软件下载&#xff1a;BetterDisplay Pro for Mac v2.0.11激活版 以下是BetterDisplay Pro的主要特点&…

ideaSSM 工程车辆人员管理系统bootstrap开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 idea 开发 SSM 工程车辆人员管理系统是一套完善的信息管理系统&#xff0c;结合SSM框架和bootstrap完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具 有完整的源代码和数据库&…

uniapp 云开发省钱之调整函数执行内存大小

我这个5块钱一个月的服务空间配置&#xff1a; 现在还只有少量的用户和自己测试之用&#xff0c;目前消耗的情况&#xff1a; 云函数的使用量还是挺高的&#xff0c;目前还是正好能覆盖一个月的使用量&#xff0c;等用户量上来肯定是不行的&#xff0c;所以得想想办法压榨一下云…