Java反射机制 (秒懂百科)

news2024/9/23 18:20:32

一、什么是反射?

 反射允许对成员变量,成员方法和构造方法的信息进行编程访问。。

反射是一种机制。对于任何一个类,都能知道这个类的所有属性和方法。对于任何一个对象,都能调用这个对象的所有属性和方法。这种动态获取类的信息和动态调用对象的能力,称为Java的反射机制。

二、获取class对象的三种方式

在Java中,可以通过以下三种方式获取Class对象,每种方式都有不同的使用场景:

1.使用Class.forName()方法:这种方式适用于只知道类的全限定名字符串时使用,可以动态地加载类并获取对应的Class对象。例如,在编写通用的代码、配置文件中指定类名字符串时,可以使用该方式获取Class对象。

try {
    Class<?> cls = Class.forName("java.lang.String");
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

2.使用.class语法:这种方式适用于我们明确知道某个类的类型时使用,直接使用类名加上.class后缀即可获取到对应的Class对象。例如,在创建实例、判断类是否是某个特定类的子类时,可以使用该方式获取Class对象。 

Class<?> cls = String.class;

 3.使用对象的getClass()方法:这种方式适用于已经存在对象并且需要获取其对应的Class对象。例如,在进行对象比较、类型判断或者动态调用对象方法时,可以使用该方式获取Class对象。

String str = "Hello";
Class<?> cls = str.getClass();

三、反射获取构造方法

使用反射获取构造方法可以通过以下步骤实现:

  1. 获取Class对象:首先,需要获取目标类的Class对象。可以使用上述提到的三种方式之一来获取Class对象。

  2. 调用getConstructors()或getDeclaredConstructors()方法:通过Class对象可以调用getConstructors()方法或getDeclaredConstructors()方法来获取构造方法数组。这两个方法分别返回公共的和所有的构造方法(包括私有和保护构造方法)。

  3. 遍历构造方法数组:得到构造方法数组后,可以使用循环遍历的方式获取每个构造方法的详细信息。

  4. 调用Constructor类的相关方法:对于每个构造方法,可以通过Constructor类的方法进行操作,比如getName()获取构造方法名、getModifiers()获取修饰符、getParameterTypes()获取参数类型等。

下面是一个示例代码,演示了如何使用反射获取构造方法:

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

public class Main {
    public static void main(String[] args) {
        try {
            // 步骤1:获取Class对象
            Class<?> cls = MyClass.class;
            
            // 步骤2:获取构造方法数组
            Constructor<?>[] constructors = cls.getDeclaredConstructors();
            
            // 步骤3:遍历构造方法数组
            for (Constructor<?> constructor : constructors) {
                // 步骤4:调用Constructor类的相关方法
                String name = constructor.getName();
                int modifiers = constructor.getModifiers();
                Class<?>[] parameterTypes = constructor.getParameterTypes();
                
                System.out.println("Constructor Name: " + name);
                System.out.println("Modifiers: " + modifiers);
                System.out.println("Parameter Types: " + Arrays.toString(parameterTypes));
                System.out.println();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyClass {
    public MyClass() {
    }
    
    private MyClass(int value) {
    }
}

输出结果:

Constructor Name: MyClass
Modifiers: 1
Parameter Types: []

Constructor Name: MyClass
Modifiers: 2
Parameter Types: [int]

四、反射获取成员变量

要利用反射获取成员变量,可以按照以下步骤进行操作:

  1. 获取目标类的Class对象:通过Class.forName()方法、obj.getClass()方法或直接使用类名.class来获取目标类的Class对象。假设目标类为MyClass

  2. 使用Class对象获取成员变量:通过调用Class对象的getField()方法或getDeclaredField()方法来获取成员变量对象。这些方法分别用于获取公共成员变量和所有成员变量(包括私有成员变量)。

  3. 操作成员变量:通过成员变量对象的get()方法获取成员变量的值,或者通过set()方法设置成员变量的新值。

下面是一个示例代码,演示了如何利用反射获取成员变量并操作它:

import java.lang.reflect.Field;

public class Main {
    public static void main(String[] args) {
        try {
            // 步骤1:获取目标类的Class对象
            Class<?> cls = MyClass.class;

            // 步骤2:获取成员变量
            Field field = cls.getDeclaredField("name");

            // 步骤3:操作成员变量
            // 设置访问权限
            field.setAccessible(true);

            // 获取成员变量的值
            Object instance = cls.newInstance();
            Object value = field.get(instance);
            System.out.println("原始值:" + value);

            // 设置新值
            field.set(instance, "New Value");
            System.out.println("修改后的值:" + field.get(instance));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyClass {
    private String name = "Original Value";
}

运行上述示例代码,将输出以下结果:

原始值:Original Value
修改后的值:New Value

在示例中,首先通过MyClass.class获取目标类MyClass的Class对象。然后使用Class对象的getDeclaredField()方法获取名为"name"的私有成员变量的Field对象。接着,通过Field对象的setAccessible(true)方法设置访问权限,允许访问私有成员变量。最后,通过Field对象的get()方法获取成员变量的值,并通过set()方法设置新的值。

请注意,获取成员变量和操作成员变量的过程中可能会抛出异常,如NoSuchFieldException、IllegalAccessException等异常,需要适当处理异常情况。

通过反射获取成员变量可以在运行时动态地访问和修改对象的属性值,对于一些特定的需求场景非常有用。但要谨慎使用,避免滥用反射机制。

五、反射获取成员方法

 下面是一个示例代码,演示了如何利用反射获取成员方法并调用它:

import java.lang.reflect.Method;

public class Main {
    public static void main(String[] args) {
        try {
            // 步骤1:获取目标类的Class对象
            Class<?> cls = MyClass.class;

            // 步骤2:获取成员方法
            Method method = cls.getDeclaredMethod("printMessage", String.class);

            // 步骤3:调用成员方法
            Object instance = cls.newInstance();
            method.invoke(instance, "Hello, Reflection!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class MyClass {
    private void printMessage(String message) {
        System.out.println("Message: " + message);
    }
}

运行上述示例代码,将输出以下结果:

Message: Hello, Reflection!

在示例中,首先通过MyClass.class获取目标类MyClass的Class对象。然后使用Class对象的getDeclaredMethod()方法获取名为"printMessage"的私有成员方法的Method对象。接着,通过Method对象的invoke()方法调用成员方法。

六、总结

 

Java反射是一种强大的机制,它允许在运行时动态地获取和操作类的成员(包括构造方法、字段和方法)。下面是对Java反射的总结:

  1. 获取Class对象:通过Class.forName()方法、obj.getClass()方法或直接使用类名.class来获取目标类的Class对象。

  2. 获取构造方法:通过调用Class对象的getConstructor()方法或getDeclaredConstructor()方法来获取构造方法对象。这些方法分别用于获取公共构造方法和所有构造方法(包括私有构造方法)。

  3. 创建实例对象:通过构造方法对象的newInstance()方法来创建构造方法的实例对象。

  4. 获取成员变量:通过调用Class对象的getField()方法或getDeclaredField()方法来获取成员变量对象。这些方法分别用于获取公共成员变量和所有成员变量(包括私有成员变量)。

  5. 操作成员变量:通过成员变量对象的get()方法获取成员变量的值,或者通过set()方法设置成员变量的新值。

  6. 获取成员方法:通过调用Class对象的getMethod()方法或getDeclaredMethod()方法来获取成员方法对象。这些方法分别用于获取公共成员方法和所有成员方法(包括私有成员方法)。

  7. 调用成员方法:通过成员方法对象的invoke()方法来调用成员方法。

通过反射可以在运行时动态地获取和操作类的成员,它提供了很大的灵活性,并可以应用于很多场景,如依赖注入、ORM框架、动态代理等。

然而,反射也需要谨慎使用,因为它会导致性能损耗,并且在一些特殊情况下可能会破坏封装性和安全性。因此,在使用反射时应该遵循最佳实践,并在必要的情况下权衡利弊。

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

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

相关文章

【推荐】深入浅出bean的生命周期

目录 1.spring 管理JavaBean的过程&#xff08;生命周期&#xff09; 2.spring的JavaBean管理中单例模式及原型&#xff08;多例&#xff09;模式 2.1 . 默认为单例&#xff0c;但是可以配置多例 2.2.举例论证 2.2.1 默认单例 2.2.2 设置多例 2.2.3单例与多例的初始化的时…

记录win 7旗舰版 “VMware Alias Manager and Ticket Service‘(VGAuhService)启动失败。

记录win 7旗舰版 "VMware Alias Manager and Ticket Service’(VGAuhService)启动失败。 描述如图 https://learn.microsoft.com/zh-CN/cpp/windows/latest-supported-vc-redist?viewmsvc-140#visual-studio-2015-2017-2019-and-2022 安装对应版本的VC 库就可以解决问…

重磅Redis 7 发布,有哪些新特性?

Redis 7.2.0 现已发布&#xff0c;这是首个 Unified Redis Release。此版本包含一系列广泛的新功能&#xff0c;以及对人工智能计划功能支持的重大投资。 公告称&#xff0c;这是 “影响最深远的版本。在每一项增强功能中&#xff0c;你都能感受到一个强烈的主题&#xff1a;让…

idea使用docker生成镜像(打包镜像,导入镜像,导出镜像)

1&#xff1a;先下载安装dockerdesktop&#xff0c;安装成功后 2&#xff1a; 在cmd执行docker -v&#xff0c;查看安装的docker版本 C:\Users\dell>docker -v Docker version 24.0.5, build ced09963&#xff1a;需要启动 dockerdesktop应用&#xff0c;才算启动docker&a…

k8s基本概念、k8s对象、三个命令玩转所有的yaml写法、给vscode安装插件、kubectl和kubelet及自动补全

文章目录 1、K8S基本概念2、kubernetes Objects&#xff08;k8s对象&#xff09;2.1、定义2.2、对象的spec和status2.3、如何写任意资源的yaml&#xff08;以Pod为例&#xff09;2.4、pod的yaml文件2.5、k8s对象yaml的结构2.6、管理k8s对象2.7、对象名称2.8、名称空间2.9、标签…

Leetcode 0814周总结

本周刷题&#xff1a; 88, 108, 121, 219, 228, 268, 283, 303, 349, 350, 414, 448 88 合并两个有序数组 nums1{1, 2, 3 ,0, 0, 0} nums2{2, 5, 6} 合成效果&#xff1a;nums1{1, 2, 2, 3, 5, 6} 思路&#xff1a;【双指针】对两个数组设置双指针&#xff0c;依次比较哪…

transform模型讲解

目录 game是游戏 与北京在一起&#xff1a;冬奥会 transform &#xff1a;encode&#xff0c;decode 12步骤 自注意力机制就是变形金刚的拆解对照&#xff1a;生成零部件V和权重K&#xff0c;前馈神经网络进行权重调节&#xff1a;初步变形 编码器Attention就是考虑上下文信…

Spring学习笔记+SpringMvc+SpringBoot学习笔记

壹、核心概念&#xff1a; 1.1. IOC和DI IOC&#xff08;Inversion of Control&#xff09;控制反转&#xff1a;对象的创建控制权由程序转移到外部&#xff0c;这种思想称为控制反转。/使用对象时&#xff0c;由主动new产生对象转换为由外部提供对象&#xff0c;此过程种对象…

阿里云服务器扩容数据盘/系统盘小记

参考&#xff1a;扩容分区和文件系统&#xff08;Linux&#xff09; 阿里云的教程写的倒是详细&#xff0c;就是太细节&#xff0c;不利于阅读。 1 确认分区数据盘的属性 运行以下命令&#xff0c;确认待扩容云盘及其分区信息。 fdisk -lu设备&#xff1a; ①&#xff1a;云…

线性筛选素数

线性筛选素数 问题 求取范围[2,n] 之间的所有素数 方法一 方法一概述 使用数字prime[i]来标记i是否为素数。初始化prime[2…n]1。 当处理到数字i时&#xff0c;若prime[i]0&#xff0c;则代表2到i-1中有i的因子&#xff0c;因此i为合数&#xff1b;若prime[i]1&#xff0c…

美团——城市低空物流无人机的设计挑战与应对

城市低空物流无人机的设计挑战与应对 强度分析 振动影响 动力设计 噪声设计 冗余备份更加性价比&#xff0c;便宜好实现 航电系统 动力系统的冗余 电池系统的冗余 通讯系统等冗余 降落冗余 安全降落 计算高效 产线标定 底层基础库 离线系统 行业公开测评 未来展望 – 导航定…

C运行时错误——error realloc(): invalid next size

在LeetCode做题时遇到一个运行时错误&#xff0c;将引起问题的原因记录一下备忘&#xff1a; 我们在malloc或calloc等API分配内存时&#xff0c;libc库除了分配给我们在参数中设定大小的内存&#xff08;可能会有内存对齐&#xff0c;实际分配的比参数设定的要多&#xff09;&…

LeetCode算法递归类—二叉树中的最大路径和

目录 124. 二叉树中的最大路径和 - 力扣&#xff08;LeetCode&#xff09; 题解&#xff1a; 代码&#xff1a; 运行结果&#xff1a; 二叉树中的 路径 被定义为一条节点序列&#xff0c;序列中每对相邻节点之间都存在一条边。同一个节点在一条路径序列中 至多出现一次 。该…

STM32驱动OLED显示菜单功能(附带oled硬件iic驱动代码)

while循环里面就写菜单退出 菜单进入 static int flag1; //记录你的选择//if(return_FLAG1)return_FLAG0;OLED_GotoXY(10,0);OLED_Puts("1 LED_TEST",&Font_11x18,1);OLED_GotoXY(10,20);OLED_Puts("2 USART_TEST",&Font_11x18,1);OLED_GotoXY…

传输请求时,如若选择包含其他TR,请留意……

以下是纯顾问群~微信群&#xff1a;SAP干货铺&#xff0c;请联系本人微信 sapliumeng。QQ群 &#xff1a;SAP干货铺&#xff0c; 群号&#xff1a;775662808所有群管理严格&#xff0c;严格禁止一切外来链接、招聘、广告等垃圾信息! 这是之前頔哥在群里说过的一个知识点&#…

谷歌浏览器插件篇之console Importer

前言 作为一名前端开发者&#xff0c;相信在开发实践中&#xff0c;使用过诸多第三方库。譬如&#xff1a;lodash、moment、dayjs、antd等数不胜数。 然每每使用&#xff0c;经起繁琐&#xff0c;便令人有反抗之意。其步骤如下&#xff1a;首先要在搭建好的项目里&#xff0c…

Lnton羚通如何使用OpenCV-Python进行轮廓汇总?

在图像处理和计算机视觉领域&#xff0c;轮廓&#xff08;Contour&#xff09;是指图像中连续的边缘部分形成的曲线&#xff0c;可以看作是物体的外边界或者是物体内部区域的边界。轮廓可以用于对象检测、图像分割、形状匹配等任务。轮廓可以通过在二值化图像中找到图像中白色&…

JDK动态代理与CGLIB动态代理

一、代理模式概述 1.1.生活中代理案例 房屋中介代理 客户手里面没有房源信息&#xff0c;找一个中介 商品代购 这些代购者可以去拿到比较低成本的商品&#xff0c;拥有自己的渠道 1.2.为什么要使用代理 对于消费者而言&#xff0c;可以减少成本&#xff0c;只需要关心自己…

深入理解Linux内核--页高速缓存

页高速缓存 页高速缓存(page cache)是Linux内核所使用的主要磁盘高速缓存。 在绝大多数情况下&#xff0c;内核在读写磁盘时都引用页高速缓存。 新页被追加到页高速缓存以满足用户态进程的读请求。 如果页不在高速缓存中&#xff0c;新页就被加到高速缓存中&#xff0c;然后用…