16 -java反射

目录

第16章 反射

16.1 反射的概念

16.2反射的作用

16.3 java.lang.Class类

16.3.1 哪些类型可以获取Class对象

16.3.2 获取Class对象的四种方式

16.4 反射的基本应用

16.4.1 获取类型的详细信息

16.4.2 创建任意引用类型的对象

16.4.3 操作任意类型的属性

16.4.4 调用任意类型的方法


第16章 反射

Java程序中,所有的对象都有两种类型:编译时类型和运行时类型,而很多时候对象的编译时类型和运行时类型不一致。

例如:某些变量或形参的类型是Object类型,但是程序却需要调用该对象运行时类型的方法,该方法不是Object中的方法,那么如何解决呢?

因为加载完类之后,就产生了一个Class类型的对象,并将引用存储到方法区,那么每一个类在方法区内存都可以找到唯一Class对象与之对应,这个对象包含了完整的类的结构信息,我们可以通过这个对象获取类的结构。这种机制就像一面镜子,Class对象像是类在镜子中的镜像,通过观察这个镜像就可以知道类的结构,所以,把这种机制形象地称为反射机制。

16.1 反射的概念

反射是Java的一种强大而灵活的特性,它允许程序在运行时获取类的信息、构造对象、调用方法和访问字段。在Java中,每个类都有一个对应的Class对象,通过这个Class对象,我们可以在运行时获取并操作类的结构。

Java反射机制主要提供了以下功能:

  • 在运行时判断任意一个对象所属的类。

  • 在运行时构造任意一个类的对象。

  • 在运行时判断任意一个类所具有的成员变量和方法。

  • 在运行时调用任意一个对象的方法。

16.2反射的作用

可以在运行时得到一个类的全部成分然后操作。

更重要的用途是适合:做Java高级框架。

16.3 java.lang.Class类

要想解剖一个类,必须先要获取到该类的Class对象。而剖析一个类或用反射解决具体的问题就是使用相关API

(1)java.lang.Class

(2)java.lang.reflect.*。

所以,Class对象是反射的根源。

16.3.1 哪些类型可以获取Class对象

哪些类型可以获取Class对象?所有Java类型

//(1)基本数据类型和void
例如:int.classvoid.class
//(2)类和接口
例如:String.classComparable.class
//(3)枚举
例如:ElementType.class
//(4)注解
例如:Override.class
//(5)数组
例如:int[].class
import java.lang.annotation.ElementType;
​
public class JavaType {public static void main(String[] args) {//(1)基本数据类型和voidClass c1 = int.class;Class c2 = void.class;
​System.out.println("c1 = " + c1);System.out.println("c2 = " + c2);//(2)类和接口Class c3 = String.class;Class c4 = Comparable.class;System.out.println("c3 = " + c3);System.out.println("c4 = " + c4);
​//(3)枚举Class c5 = ElementType.class;System.out.println("c5 = " + c5);
​//(4)注解Class c6 = Override.class;System.out.println("c6 = " + c6);
​//(5)数组Class c7 = int[].class;Class c9 = String[].class;Class c8 = int[][].class;System.out.println("c7 = " + c7);System.out.println("c8 = " + c8);System.out.println("c9 = " + c9);}
}

16.3.2 获取Class对象的四种方式

(1)类型名.class

要求编译期间已知类型

(2)对象.getClass()

获取对象的运行时类型

(3)Class.forName(类型全名称)

可以获取编译期间未知的类型

(4)ClassLoader的类加载器对象.loadClass(类型全名称)

可以用系统类加载对象或自定义加载器对象加载指定路径下的类型

public class GetClassObject {@Testpublic void test01() throws ClassNotFoundException{Class c1 = GetClassObject.class;GetClassObject obj = new GetClassObject();Class c2 = obj.getClass();Class c3 = Class.forName("com.haogu.classtype.GetClassObject");Class c4 = ClassLoader.getSystemClassLoader().loadClass("com.haogu.classtype.GetClassObject");
​System.out.println("c1 = " + c1);System.out.println("c2 = " + c2);System.out.println("c3 = " + c3);System.out.println("c4 = " + c4);
​System.out.println(c1 == c2);System.out.println(c1 == c3);System.out.println(c1 == c4);}
​@Testpublic void test02(){int[] arr1 = {1,2,3,4,5};int[] arr2 = {10,34,5,66,34,22};int[][] arr3 = {{1,2,3,4},{4,5,6,7}};String[] arr4 = {"hello","world"};
​Class c1 = arr1.getClass();Class c2 = arr2.getClass();Class c3 = arr3.getClass();Class c4 = arr4.getClass();
​System.out.println("c1 = " + c1);System.out.println("c2 = " + c2);System.out.println("c3 = " + c3);System.out.println("c4 = " + c4);System.out.println(c1 == c2);System.out.println(c1 == c3);System.out.println(c1 == c4);System.out.println(c3 == c4);}
}

16.4 反射的基本应用

Java 反射的主要组成部分有4个:

正在运行的 Java 应用程序中的类:Class。

在运行时,可以直接得到这个类的成员变量对象:Field

在运行时,可以直接得到这个类的构造器对象:Constructor

在运行时,可以直接得到这个类的成员方法对象:Method

这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。

16.4.1 获取类型的详细信息

可以获取:包、修饰符、类型名、父类(包括泛型父类)、父接口(包括泛型父接口)、成员(属性、构造器、方法)、注解(类上的、方法上的、属性上的)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
​
public class TestClassInfo {public static void main(String[] args) throws Exception {//1、先得到某个类型的Class对象Class clazz = String.class;//比喻clazz好比是镜子中的影子
​//2、获取类信息//(1)获取包对象,即所有java的包,都是Package的对象Package pkg = clazz.getPackage();System.out.println("包名:" + pkg.getName());
​//(2)获取修饰符int mod = clazz.getModifiers();System.out.println("类的修饰符有:" + Modifier.toString(mod));
​//(3)类型名String name = clazz.getName();System.out.println("类名:" + name);
​//(4)父类,父类也有父类对应的Class对象Class superclass = clazz.getSuperclass();System.out.println("父类:" + superclass);
​//(5)父接口们System.out.println("父接口们:");Class[] interfaces = clazz.getInterfaces();for (Class iter : interfaces) {System.out.println(iter);}
​//(6)类的属性,  你声明的一个属性,它是Field的对象
/*      Field clazz.getField(name)  根据属性名获取一个属性对象,但是只能得到公共的Field[] clazz.getFields();  获取所有公共的属性Field clazz.getDeclaredField(name)  根据属性名获取一个属性对象,可以获取已声明的Field[] clazz.getDeclaredFields()   获取所有已声明的属性*/
//        Field valueField = clazz.getDeclaredField("value");
//      System.out.println("valueField = " +valueField);
​System.out.println("------------------------------");System.out.println("成员如下:");System.out.println("属性有:");Field[] declaredFields = clazz.getDeclaredFields();for (Field field : declaredFields) {//修饰符、数据类型、属性名int modifiers = field.getModifiers();System.out.println("属性的修饰符:" + Modifier.toString(modifiers));
​String name2 = field.getName();System.out.println("属性名:" + name2);
​Class<?> type = field.getType();System.out.println("属性的数据类型:" + type);}System.out.println("-------------------------");//(7)构造器们System.out.println("构造器列表:");Constructor[] constructors = clazz.getDeclaredConstructors();for (int i=0; i<constructors.length; i++) {Constructor constructor = constructors[i];System.out.println("第" + (i+1) +"个构造器:");//修饰符、构造器名称、构造器形参列表  、抛出异常列表int modifiers = constructor.getModifiers();System.out.println("构造器的修饰符:" + Modifier.toString(modifiers));
​String name2 = constructor.getName();System.out.println("构造器名:" + name2);
​//形参列表System.out.println("形参列表:");Class[] parameterTypes = constructor.getParameterTypes();for (Class parameterType : parameterTypes) {System.out.println(parameterType);}
​//异常列表System.out.println("异常列表:");Class<?>[] exceptionTypes = constructor.getExceptionTypes();for (Class<?> exceptionType : exceptionTypes) {System.out.println(exceptionType);}System.out.println();}System.out.println("---------------------------------");//(8)方法们System.out.println("方法列表:");Method[] declaredMethods = clazz.getDeclaredMethods();for (int i=0; i<declaredMethods.length; i++) {Method method = declaredMethods[i];System.out.println("第" + (i+1) +"个方法:");//修饰符、返回值类型、方法名、形参列表 、异常列表int modifiers = method.getModifiers();System.out.println("方法的修饰符:" + Modifier.toString(modifiers));
​Class<?> returnType = method.getReturnType();System.out.println("返回值类型:" + returnType);
​String name2 = method.getName();System.out.println("方法名:" + name2);
​//形参列表System.out.println("形参列表:");Class[] parameterTypes = method.getParameterTypes();for (Class parameterType : parameterTypes) {System.out.println(parameterType);}
​//异常列表System.out.println("异常列表:");Class<?>[] exceptionTypes = method.getExceptionTypes();for (Class<?> exceptionType : exceptionTypes) {System.out.println(exceptionType);}System.out.println();}
​}
}
​

16.4.2 创建任意引用类型的对象

两种方式:

1、直接通过Class对象来实例化(要求必须有公共的无参构造)

2、通过获取构造器对象来进行实例化

方式一的步骤:

(1)获取该类型的Class对象(2)创建对象

方式二的步骤:

(1)获取该类型的Class对象(2)获取构造器对象(3)创建对象

16.4.3 操作任意类型的属性

(1)获取该类型的Class对象

Class clazz = Class.forName("包.类名");

(2)获取属性对象

Field field = clazz.getDeclaredField("属性名");

(3)如果属性的权限修饰符不是public,那么需要设置属性可访问

field.setAccessible(true);

(4)创建实例对象:如果操作的是非静态属性,需要创建实例对象

Object obj = clazz.newInstance(); //有公共的无参构造

Object obj = 构造器对象.newInstance(实参...);//通过特定构造器对象创建实例对象

(4)设置属性值

field.set(obj,"属性值");

如果操作静态变量,那么实例对象可以省略,用null表示

(5)获取属性值

Object value = field.get(obj);

如果操作静态变量,那么实例对象可以省略,用null表示

16.4.4 调用任意类型的方法

(1)获取该类型的Class对象

Class clazz = Class.forName("包.类名");

(2)创建实例对象

Object obj = clazz.newInstance();

(3)获取方法对象

Method method = clazz.getDeclaredMethod("方法名",方法的形参类型列表);

(4)调用方法

Object result = method.invoke(obj, 方法的实参值列表);

如果方法的权限修饰符修饰的范围不可见,可以调用setAccessible(true)

如果方法是静态方法,实例对象可以省略,用null代替

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

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

相关文章

【JS基础知识07】函数

一&#xff1a;函数是什么以及函数作用 1 函数是什么 函数是经过封装、调用后&#xff0c;能够完成特定任务的代码块 2 函数的作用 仅需“函数名(实参)”就可以调用函数&#xff0c;起到精简代码&#xff0c;提高开发效率的作用 二&#xff1a;函数使用 1 语法规则&#…

光耦的工作原理

一、光电耦合器简介 光电耦合器主要是一种围绕光作为媒介的光电转换元器件&#xff0c;能够实现光到电、电到光之间的自由转换。我们又可以称之为光电隔离器&#xff0c;之所以这么称呼&#xff0c;主要是因为光电耦合器能够很好的对电路中的电信号起到隔离的作用。有效的保护…

如何使用 .htaccess 删除文件扩展名

本周有一个客户&#xff0c;购买Hostease的虚拟主机&#xff0c;询问我们的在线客服&#xff0c;如何使用 .htaccess 删除文件扩展名&#xff1f;我们为用户提供相关教程&#xff0c;用户很快解决了遇到的问题。在此&#xff0c;我们分享这个操作教程&#xff0c;希望可以对您有…

如何在中国网上发布文章

随着互联网的迅猛发展&#xff0c;网上发布文章已经成为一种重要的传播方式。而在中国&#xff0c;作为世界上最大的互联网市场&#xff0c;如何在中国网上发布文章成为了许多人关注的焦点。媒介多多网发稿平台作为一个专业的发稿平台&#xff0c;为广大作者提供了很好的发布文…

计算机系统基础实验三(解了但尽量理解)

一.准备阶段 1、下载好32位的实验代码后&#xff0c;将文件解压缩并且通过共享文件夹操作将文件添加到虚拟机中&#xff0c;双击查看bomb.c代码&#xff0c;将c代码完整看了一遍&#xff0c;发现看这里的c代码是无从下手的&#xff0c;代码中只含有主函数&#xff0c;触发炸弹…

AI 画图真刺激,手把手教你如何用 ComfyUI 来画出刺激的图

目前 AI 绘画领域的产品非常多&#xff0c;比如 Midjourney、Dalle3、Stability AI 等等&#xff0c;这些产品大体上可以分为两类&#xff1a; 模型与产品深度融合&#xff1a;比如 Midjourney、Dalle3 等等。模型与产品分离&#xff1a;比如 SD Web UI、ComfyUI 等等。 对于…

宏基因组分析流程(Metagenomic workflow)202405|持续更新

Logs 增加R包pctax内的一些帮助上游分析的小脚本&#xff08;2024.03.03&#xff09;增加Mmseqs2用于去冗余&#xff0c;基因聚类的速度非常快&#xff0c;且随序列量线性增长&#xff08;2024.03.12&#xff09;更新全文细节&#xff08;2024.05.29&#xff09; 注意&#x…

LeetCode2336无限集中的最小数字

题目描述 现有一个包含所有正整数的集合 [1, 2, 3, 4, 5, …] 。实现 SmallestInfiniteSet 类&#xff1a;SmallestInfiniteSet() 初始化 SmallestInfiniteSet 对象以包含 所有 正整数。int popSmallest() 移除 并返回该无限集中的最小整数。void addBack(int num) 如果正整数 …

mac m1安装homebrew管理工具(brew命令)完整流程

背景 因为mac上的brew很久没用了&#xff0c;版本非常旧&#xff0c;随着mac os的更新&#xff0c;本机的homebrew大部分的功能都无法使用&#xff0c;幸好过去通过brew安装的工具比较少&#xff0c;于是决定重新安装一遍brew。 卸载旧版brew 法一&#xff1a;通过使用线上…

力扣:104. 二叉树的最大深度

104. 二叉树的最大深度 给定一个二叉树 root &#xff0c;返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1&#xff1a; 输入&#xff1a;root [3,9,20,null,null,15,7] 输出&#xff1a;3示例 2&#xff1a; 输入&#xff1a…

C++语言·list链表(下)

还是之前说的&#xff0c;因为要写模板&#xff0c;为了避免链接出现问题&#xff0c;我们将所有内容都写到一个文件中去。首先就是画出链表的框架 链表本身只需要一个头节点就足以找到整条链表&#xff0c;而需要它拼接的节点我们再写一个模板。而我们知道list是一个带头双向循…

Verilog HDL基础知识(一)

引言&#xff1a;本文我们介绍Verilog HDL的基础知识&#xff0c;重点对Verilog HDL的基本语法及其应用要点进行介绍。 1. Verilog HDL概述 什么是Verilog&#xff1f;Verilog是IEEE标准的硬件描述语言&#xff0c;一种基于文本的语言&#xff0c;用于描述最终将在硬件中实现…

数据库设计实例---学习数据库最重要的应用之一

一、引言【可忽略】 在学习“数据库系统概述”这门课程时&#xff0c;我一直很好奇&#xff0c;这样一门必修课&#xff0c;究竟教会了我什么呢&#xff1f; 由于下课后&#xff0c;&#xff0c;没有拓展自己的眼界&#xff0c;上课时又局限于课堂上老师的讲课水平&#xff0c;…

探索数组处理:奇数的筛选与替换

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一、数组中的奇数筛选 二、将奇数替换为负一 总结 一、数组中的奇数筛选 在处理数组数据时…

【Qt】初识

一、使用Label显示Hello World 1.ui设计 可以在Qt Designer中拖拽方式进行创建 2.代码方式 在myqwidget.cpp文件中添加下列代码 二、对象树 我们在堆上创建了QLabel类的对象。但是我们没有去delete&#xff0c;这样会产生内存泄漏吗&#xff1f; 答案是不会。label对象会在…

ChatGPT的基本原理是什么?又该如何提高其准确性?

在深入探索如何提升ChatGPT的准确性之前&#xff0c;让我们先来了解一下它的工作原理吧。ChatGPT是一种基于深度学习的自然语言生成模型&#xff0c;它通过预训练和微调两个关键步骤来学习和理解自然语言。 在预训练阶段&#xff0c;ChatGPT会接触到大规模的文本数据集&#x…

输入输出(1)——C++的输入输出概述

目录 一、C的输入输出 (一) C的输入输出 (二&#xff09;C语言的scanf和printf 二、C的输入输出流 (一) iostream类库中有关的类 (二&#xff09; iostream.h头文件的流对象和重载运算符 一、C的输入输出 (一) C的输入输出 之前用到的输入输出&#xff0c;都是以终端…

在做题中学习(62):矩阵区域和

1314. 矩阵区域和 - 力扣&#xff08;LeetCode&#xff09; 解法&#xff1a;二维前缀和 思路&#xff1a;读题画图才能理解意思&#xff1a;dun点点的是mat中的一个数&#xff0c;而要求的answer同位置的数 以点为中心上下左右延长 k 个单位所围成长方形的和。 因为最后answ…

IPV4地址介绍

4.1IP地址简介 目前的全球因特网所采用的协议族是TCP/IP协议族。IP是TCP/IP协议族中网络层的协议&#xff0c;是TCP/IP协议族的核心协议。IP协议定义了一种地址编码&#xff0c;称为IP地址&#xff0c;它是网络中网络段、网络设备接口、主机的编码&#xff0c;它并不是一种物理…

Linux离线一键安装Docker及docker-compose环境

背景&#xff1a; 在当前软件部署运维环境中由于Docker容器化优势越来越明显&#xff0c;因些被许多公司运维所采用&#xff0c;那首先如何快速安装Docker及docker-compose基础环境就第一时间被人们关注&#xff0c;本人同样在经过多次手工逐条用命令安装的过程&#xff0c;整理…