Java——反射

news2025/7/19 7:01:44

目录

5 反射


5 反射

  • 类信息:方法、变量、构造器、继承和实现的类或接口。
  • 反射:反射是 Java 中一项强大的特性,它赋予了程序在运行时动态获取类的信息,并能够调用类的方法、访问类的字段以及操作构造函数等的能力。通过反射,我们可以突破编译期的限制,在运行时对类进行灵活的操作。
  • 获取类信息的前提:生成类对象
  • 类的生命周期与反射关联:

在 Java 中,类的生命周期有着明确的阶段。首先,我们编写的.java源文件通过javac命令进行编译,生成.class字节码文件。之后,类加载器会将.class文件加载到内存中,在元空间(Java 虚拟机专门为存储类的元数据等开辟的内存空间 )中生成类对象。而反射机制的前提就是生成类对象,只有获得了类对象,我们才能进一步获取类的详细信息。

  • 元空间:内存专门为Java开辟的空间。

  • 反射获取类信息的方式

从类对象出发,我们可以从多个维度获取类的信息:

变量相关:

  1. getDeclaredFields() :该方法能够获取类中所有权限修饰的成员变量,包括私有、受保护、包访问以及公共变量。
  2. getDeclaredField(name) :根据指定的变量名获取对应的成员变量,同样不受访问权限限制。
  3. getFields() :用于获取类中所有具有公共访问权限的成员变量。
  4. getField(name) :根据指定名称获取类中具有公共访问权限的成员变量。

对于私有变量,如果要进行访问和操作,需要通过 setAccessible(true) 进行暴力反射,绕过访问权限修饰符的安全检查,之后便可以利用 set() 方法设置变量值,利用 get() 方法获取变量值 。

方法相关:

  1. getDeclaredMethods() :可以获取类中所有权限修饰的成员方法。
  2. getDeclaredMethod(name) :根据指定的方法名获取对应的成员方法。
  3. getMethods() :获取类中所有具有公共访问权限的成员方法。
  4. getMethod(name) :根据指定名称获取类中具有公共访问权限的成员方法。

对于私有方法,同样先使用 setAccessible(true) 进行暴力反射,然后通过 invoke() 方法执行方法,也可以使用 getName() 方法获取方法名。


构造方法相关:

  1. getDeclaredConstructors() :获取类中所有权限修饰的构造方法。
  2. getDeclaredConstructor() :获取指定的无参构造方法。
  3. getDeclaredConstructor(xx.class) :获取指定参数类型的有参构造方法。
  4. getConstructors() :获取类中所有具有公共访问权限的构造方法。

对于私有构造方法,使用 setAccessible(true) 进行暴力反射后,可利用构造方法创建对象,例如通过 newInstance() 方法。如果类有无参构造方法,还可以通过类对象直接调用 class3.newInstance() 来创建实例。


获取类名称的方法
通过反射,还可以获取类的名称。getName() 方法会返回类的全限定名(包名 + 类名 ),而 getSimpleName() 方法则只返回类名本身。

  • 实例代码

如下,一共有两个版本,一个是按照上面的思路,先生成类对象,在从变量、方法构造方法的角度分别解释。第二个版本则是按照反射获取类信息的步骤,按照周一步一步来。

  • 第一个版本:
package com.qcby.反射;

public class Person {
	private String name;
	private int age;
	public String country;
	public int height;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	public Person(String name, int age, String country, int height) {
		super();
		this.name = name;
		this.age = age;
		this.country = country;
		this.height = height;
	}
	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Person() {
		super();
	}
	private Person(String country) {
		super();
		this.country = country;
	}
	
	
	
	
	
	private void run() {
		System.out.println("跑跑跑...");
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", country=" + country + ", height=" + height + "]";
	}
	
	
}
package com.qcby.反射;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class Test {
	public static void main(String[] args) throws Exception {
		
		//创建对象
		Person person1 = new Person();
		Person person2 = new Person("李四",30,"中国",170);
		Person person3 = new Person("cici",35,"美国",160);
		
		//反射类里面获取类信息的步骤
		//第一步获取 类对象 
		
		//对象阶段获取类对象  对象名.getClass()
		Person person = new Person();
		Class class1 = person.getClass();
		
		//元空间阶段获取类对象 类名.class
		Class class2 = Person.class;
		
		//硬盘阶段获取类对象 Class.forName(类全名)   包名+类名
		Class class3 =  Class.forName("com.qcby.反射.Person");
     	System.out.println(class1);//com.qcby.反射.Person
		System.out.println(class2);//com.qcby.反射.Person
    	System.out.println(class3);//com.qcby.反射.Person
		System.out.println(class1==class2);//true,因为同一个类在类加载器加载文件的时候,只会执行一次。true也说明了他们同时指向同一个内存空间。
		System.out.println(class1==class3);//true
		
		//第二步  通过类对象 获取类信息
                //类信息存储的形式一般有两种,所以对于获取可以直接获取或者获取相关的集合		
  
		//获取变量
		System.out.println("========所有访问权限的变量==========");
		Field[] fields =  class3.getDeclaredFields();
		for(Field a:fields) {
			System.out.println(a);
		}
		
		System.out.println("======指定变量============");
		Field height =  class3.getDeclaredField("height");
		Field name =  class3.getDeclaredField("name");
		Field country =  class3.getDeclaredField("country");
		Field age =  class3.getDeclaredField("age");
		System.out.println(age);
		
		System.out.println("======公共访问权限变量============");
		Field[] fields1 = class3.getFields();
		for(Field a:fields1) {
			System.out.println(a);
		}
		
		System.out.println("======指定公共访问权限变量============");	
		Field height1 = class3.getField("height");//只可以获取public类型的变量,private不可以

		//拿到变量后就可以设置值、获取值,如果变量是private权限,直接使用会抛出异常,需要先暴力反射
		//通过set()和get()设置和获取值
		//设置值
		height.set(person1, 180);//name是private,如果通过这种方式会抛出异常,need先暴力反射
		name.setAccessible(true);//暴力反射,忽略访问权限修饰符的安全检查
		age.setAccessible(true);//暴力反射
		name.set(person1, "张三");
		System.out.println(person1);
		//获取值
		System.out.println(height.get(person2));
		System.out.println(name.get(person2));
		System.out.println(age.get(person2));
		System.out.println(country.get(person2));
		
		
		
		//获取方法
		System.out.println("=========所有访问权限的方法==================");
		Method[] methods = class3.getDeclaredMethods();
		for(Method a:methods) {
			System.out.println(a);
		}
		System.out.println("=========所有指定的方法==================");
		
		Method run_method = class3.getDeclaredMethod("run");
		System.out.println(run_method);
		Method getName_method = class3.getDeclaredMethod("getName");
		System.out.println(getName_method);
		Method setAge_method = class3.getDeclaredMethod("setAge",int.class);//前面获取的方法无形参可以直接用函数名,但是setAge有形参,需要传参数,不然会抛出异常
		System.out.println(setAge_method);
		
		System.out.println("=========公共访问权限的方法==================");
		Method[] methods1 = class3.getMethods();
		for(Method a:methods1) {
			System.out.println(a);
		}
		
		System.out.println("=========指定公共访问权限的方法==================");
		Method getName_method1 = class3.getMethod("getName");
		System.out.println(getName_method1);
		Method setAge_method1 = class3.getMethod("setAge",int.class);
		System.out.println(setAge_method1);
		
		//拿到方法后就可以执行方法
		Object name = getName_method.invoke(person3);
		System.out.println(name);
		setAge_method.invoke(person3, 50);//有行参的要传参
		System.out.println(person3);
		run_method.setAccessible(true);//private修饰的方法,要先暴力反射
		run_method.invoke(person2);
		
		System.out.println(run_method.getName());//获取方法名字,如果不知道方法名字要先获取,知道就可以直接获取方法
		
		
		//获取构造方法
		
		System.out.println("============获取所有构造方法==============");
		Constructor[] constructors  =class3.getDeclaredConstructors();
		for(Constructor a:constructors) {
			System.out.println(a);
		}
		System.out.println("============获取无参构造方法==============");
		Constructor no_parameter = class3.getDeclaredConstructor();
		System.out.println(no_parameter);
		
		System.out.println("============获取有参构造方法==============");
		Constructor have_two_parameter = class3.getDeclaredConstructor(String.class,int.class);
		System.out.println(have_two_parameter);
		
		Constructor have_one_parameter = class3.getDeclaredConstructor(String.class);
		System.out.println(have_one_parameter);
		
		System.out.println("============获取公共的构造方法==============");
		Constructor[] constructors1  =class3.getConstructors();
		for(Constructor a:constructors1) {
			System.out.println(a);
		}
		
		//获取构造方法后就可以创建对象
		
		Object person1 = no_parameter.newInstance();
		System.out.println(person1);
		
		Object person2 = have_two_parameter.newInstance("李华",21);
		System.out.println(person2);
		
		have_one_parameter.setAccessible(true);//private修饰的构造方法,需要先暴力反射
		Object person3 = have_one_parameter.newInstance("美国");
		System.out.println(person3);
		
		
		
		//特例,无参构造方法可以通过类对象直接调用
		Object person4 = class3.newInstance();
		System.out.println(person4);
		
		
		//获取名称
		//System.out.println(class3.getName());//获取包名加类名
		//System.out.println(class3.getSimpleName());//只获取类名
		
	}
}
  • 第二个版本
package com.qcby.反射;

public class Cat implements Jump,Run{
	private int age;
	public String name;
	protected String color;
	double height;
	public Cat(int age,String name,String color,double height) {
		this.age = age;
		this.name = name;
		this.color = color;
		this.height = height;
	}
	private Cat() {
		
	}
	Cat(String color){
		this.color = color;
	}
	public void run(String name,int age,double height) {
		System.out.println("小猫的名字叫"+name);
	}
	public void run(String name) {
		System.out.println("小猫的名字叫"+name);
	}
	
	private int setAge(int age) {
		return age;
	}
	
	void fly() {
		System.out.println("猫不会飞");
	}
}
package com.qcby.反射;

public interface Jump {

}
package com.qcby.反射;

public interface Run {

}

package com.qcby.反射;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class Test2 {
	public static void main(String[] args) throws Exception{
		//获取类对象
		Class clazz = Class.forName("com.qcby.反射.Cat");
		Class clazz1 = Class.forName("com.qcby.反射.Cat");	
		Class clazz2 = Cat.class;
				
		Cat cat = new Cat("黑色");
		Class clazz3 = cat.getClass();
		System.out.println(clazz1==clazz2);
		System.out.println(clazz2==clazz3);
		//说明clazz1、clazz2和clazz3指向同一个内存空间
		System.out.println("---------------");
		
		//变量
		Field[] fields = clazz.getDeclaredFields();
		System.out.println(Arrays.toString(fields));
		
		Field ageFiled = clazz.getDeclaredField("age");
		System.out.println(ageFiled);
		
		Field nameFiled = clazz.getDeclaredField("name");
		System.out.println(nameFiled);
		
		Field colorFiled = clazz.getDeclaredField("color");
		System.out.println(colorFiled);
		
		Field heightFiled = clazz.getDeclaredField("height");
		System.out.println(heightFiled);
		
		Field[] fields1 = clazz.getFields();
		System.out.println(Arrays.toString(fields1));
		Field nameFiled1 = clazz.getField("name");
		System.out.println(nameFiled);
		//Field ageFiled1 = clazz.getField("age");
		//System.out.println(ageFiled);
		System.out.println("----------------");
		
		//方法
		Method[] methods = clazz.getDeclaredMethods();
		System.out.println(Arrays.toString(methods));
		
		Method[] methods1 = clazz.getMethods();
		System.out.println(Arrays.toString(methods1));
		
		Method runMethod1 = clazz.getDeclaredMethod("run", String.class);
		System.out.println(runMethod1);
		
		Method runMethod2 = clazz.getMethod("run",String.class);
		System.out.println(runMethod2);
		
		Method flyMethod1 = clazz.getDeclaredMethod("fly");
		System.out.println(flyMethod1);
		System.out.println("---------------");
		
		//构造函数
		Constructor[] constructors = clazz.getConstructors();
		System.out.println(Arrays.toString(constructors));
		
		Constructor[] constructors1 = clazz.getDeclaredConstructors();
		System.out.println(Arrays.toString(constructors1));
		
		Constructor constructor1 = clazz.getDeclaredConstructor();
		System.out.println(constructor1);
		
		Constructor constructor2 = clazz.getDeclaredConstructor(String.class);
		System.out.println(constructor2);
		
		//Constructor constructor3 = clazz.getConstructor();
		//System.out.println(constructor3);
		System.out.println("----------");
		
		//接口
		Class[] classes = clazz.getInterfaces();
		System.out.println(Arrays.toString(classes));
		
		
		//拿到类信息后可以进行相应的操作,如果拿到的信息是private修饰,使用时要先进行暴力反射,否则会抛出异常
		
		//拿到构造方法 ->创建对象
		Constructor c1 = clazz.getDeclaredConstructor(int.class,String.class,String.class,double.class);
		Cat cat1 = (Cat) c1.newInstance(20,"小黑","黑色",240.5);
		
		Constructor c2 = clazz.getDeclaredConstructor();
		c2.setAccessible(true);//暴力反射
		Cat cat2 = (Cat) c2.newInstance();
		
		Constructor c3 = clazz.getDeclaredConstructor(String.class);
		Cat cat3 = (Cat) c3.newInstance("白色");
		
		//拿到变量 ->赋值和获取
		ageFiled.setAccessible(true);//暴力反射
		ageFiled.set(cat1, 88);
		int age = (int) ageFiled.get(cat1);
		System.out.println(age);
		
		nameFiled.set(cat1, "小花");
		System.out.println(nameFiled.get(cat1));
		
		//拿到方法->使用方法
		runMethod1.invoke(cat1, "小花");
		
		Method method2 = clazz.getDeclaredMethod("setAge", int.class);
		method2.setAccessible(true);
		System.out.println(method2.invoke(cat1, 18));
		
	}
	
	
	
}
  • 总结:

反射获取类信息的步骤:

  1. 生成类对象。
  2. 通过类对象获取类信息。
  3. 拿到类信息后可以进行相应的操作,如果拿到的信息是private修饰,使用时要先进行暴力反射,否则会抛出异常。拿到构造方法后可以创建对象;拿到变量后可以赋值和获取值;拿到方法后可以执行方法。

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

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

相关文章

本地玩AI绘画 | StableDiffusion安装到绘画

环境须知 Cuda必须安装 不需要安装Python,因为该项目会自动安装Python3.10的虚拟环境 1.下载StableDiffusionWebUI压缩包并解压 下载方式一: 从Github下载https://github.com/AUTOMATIC1111/stable-diffusion-webui 的压缩包,解压后名为…

project从入门到精通(四)

目录 日程表的设置和妙用 为日程表视图添加任务 用日程表视图的好处 ​编辑 查找任务的前置任务和后续任务 方法1:采用复合视图的方式 方法3:关系图法 方法4:通过任务路径的方式检查所选任务的前置任务 前置任务和驱动前置任务的区…

git项目迁移,包括所有的提交记录和分支 gitlab迁移到gitblit

之前git都是全新项目上传,没有迁移过,因为迁移的话要考虑已有项目上的分支都要迁移过去,提交记录能迁移就好;分支如果按照全新项目上传的方式需要新git手动创建好老git已有分支,在手动一个一个克隆老项目分支代码依次提…

港大今年开源了哪些SLAM算法?

过去的5个月,香港大学 MaRS 实验室陆续开源了四套面向无人机的在线 SLAM 框架:**FAST-LIVO2 、Point-LIO(grid-map 分支) 、Voxel-SLAM 、Swarm-LIO2 **。这四套框架覆盖了单机三传感器融合、高带宽高速机动、长时间多级地图优化以…

Godot4.3类星露谷游戏开发之【昼夜循环】

千里之行,始于足下 文章目录 零、 笔记一、创造时间二、产生颜色三、搭建测试环境四、测试五、免费开源资产包 零、 笔记 为了让游戏可以拥有白天和黑夜,我们需要像上帝一样,在游戏中创造时间的规则,并在不同的时间点产生不同的颜…

修复笔记:获取 torch._dynamo 的详细日志信息

一、问题描述 在运行项目时,遇到与 torch._dynamo 相关的报错,并且希望获取更详细的日志信息以便于进一步诊断问题。 二、相关环境变量设置 通过设置环境变量,可以获得更详细的日志信息: set TORCH_LOGSdynamo set TORCHDYNAM…

Windows平台下的Qt发布版程序打包成exe可执行文件(带图标)|Qt|C++

首先先找一个可执行文件的图标 可以去阿里的矢量图库里找 iconfont-阿里巴巴矢量图标库 找到想要的图标下载下来 此时的图标是png格式的,我们要转到icon格式的文件 要使用到一个工具Drop Icons_2.1.1.rar - 蓝奏云 生成icon文件后把icon文件放到你项目的根目录下…

CSS--图片链接垂直居中展示的方法

原文网址&#xff1a;CSS--图片链接垂直居中展示的方法-CSDN博客 简介 本文介绍CSS图片链接垂直居中展示的方法。 图片链接 问题复现 源码 <html xml:lang"cn" lang"cn"><head><meta http-equiv"Content-Type" content&quo…

TRAE 配置blender MCP AI自动3D建模

BlenderMCP - Blender模型上下文协议集成 BlenderMCP通过模型上下文协议(MCP)将Blender连接到Claude AI&#xff0c;允许Claude直接与Blender交互并控制Blender。这种集成实现了即时辅助的3D建模、场景创建和操纵。 1.第一步下载 MCP插件(addon.py):Blender插件&#xff0c;在…

VUE2课程计划表练习

主要练习数据变量对象 以下是修正后的完整代码&#xff1a; //javascript export default {data() {return {list: [{ id: 1, subject: Vue.js 前端实战开发, content: 学习指令&#xff0c;例如 v-if、v-for、v-model 等, place: 自习室, status: false }// 可以在这里添加更…

2025年软件工程与数据挖掘国际会议(SEDM 2025)

2025 International Conference on Software Engineering and Data Mining 一、大会信息 会议简称&#xff1a;SEDM 2025 大会地点&#xff1a;中国太原 收录检索&#xff1a;提交Ei Compendex,CPCI,CNKI,Google Scholar等 二、会议简介 2025年软件开发与数据挖掘国际会议于…

.NET高频技术点(持续更新中)

1. .NET 框架概述 .NET 框架的发展历程.NET Core 与 .NET Framework 的区别.NET 5 及后续版本的统一平台 2. C# 语言特性 异步编程&#xff08;async/await&#xff09;LINQ&#xff08;Language Integrated Query&#xff09;泛型与集合委托与事件属性与索引器 3. ASP.NET…

pandas中的数据聚合函数:`pivot_table` 和 `groupby`有啥不同?

pivot_table 和 groupby 是 pandas 中两种常用的数据聚合方法&#xff0c;它们都能实现数据分组和汇总&#xff0c;但在使用方式和输出结构上有显著区别。 0. 基本介绍 groupby分组聚合 groupby 是 Pandas 库中的一个功能强大的方法&#xff0c;用于根据一个或多个列对数据进…

对golang中CSP的理解

概念&#xff1a; CSP模型&#xff0c;即通信顺序进程模型&#xff0c;是由英国计算机科学家C.A.R. Hoare于1978年提出的。该模型强调进程之间通过通道&#xff08;channel&#xff09;进行通信&#xff0c;并通过消息传递来协调并发执行的进程。CSP模型的核心思想是“不要通过…

【LunarVim】CMake LSP配置

在 LunarVim 中为 CMakeLists.txt 文件启用代码提示&#xff08;如补全和语义高亮&#xff09;&#xff0c;需要安装支持 CMake 的 LSP&#xff08;语言服务器&#xff09;和适当的插件。以下是完整配置指南&#xff1a; 1、配置流程 1.1 安装cmake-language-server 通过 Ma…

Mkdocs页面如何嵌入PDF

嵌入PDF 嵌入PDF代码 &#xff0c;注意PDF的相对地址 <iframe src"../个人简历.pdf (相对地址)" width"100%" height"800px" style"border: 1px solid #ccc; overflow: auto;"></iframe>我的完整代码&#xff1a; <d…

融合静态图与动态智能:重构下一代智能系统架构

引言&#xff1a;智能系统的分裂 当前的大模型系统架构正处于两个极端之间&#xff1a; 动态智能体系统&#xff1a;依赖语言模型动态决策、自由组合任务&#xff0c;智能灵活但稳定性差&#xff1b; 静态流程图系统&#xff1a;具备强工程能力&#xff0c;可控可靠&#xf…

WORD压缩两个免费方法

日常办公和学习中&#xff0c;Word文档常常因为包含大量图片、图表或复杂格式而导致文件体积过大&#xff0c;带来诸多不便&#xff0c;比如 邮件发送受限&#xff1a;许多邮箱附件限制在10-25MB&#xff0c;大文件无法直接发送 存储空间占用&#xff1a;大量文档占用硬盘或云…

skywalking服务安装与启动

skywalking服务安装并启动 1、介绍2、下载apache-skywalking-apm3、解压缩文件4、创建数据库及用户5、修改配置文件6、下载 MySQL JDBC 驱动7、启动 OAP Serve,需要jkd11,需指定jkd版本,可以修改文件oapService.sh8、启动 Web UI,需要jkd11,需指定jkd版本,可以修改文件oapServi…

Qt 中信号与槽(signal-slot)机制支持 多种连接方式(ConnectionType)

Qt 中信号与槽&#xff08;signal-slot&#xff09;机制支持 多种连接方式&#xff08;ConnectionType&#xff09; Qt 中信号与槽&#xff08;signal-slot&#xff09;机制支持 多种连接方式&#xff08;ConnectionType&#xff09;&#xff0c;用于控制信号发出后如何调用槽…