Java反射全面详解

news2024/11/17 7:22:23

1. 什么是反射?

首先听这个名字就有些疑惑,什么是反射,它能用来干什么呢?

Java官方对反射的解释是 "反射允许对封装类的字段,方法和构造函数进行编程式访问"。这里的字段指的就是成员变量,方法指的就是成员方法,构造函数就是构造方法。        

2. 反射有什么用?

我们知道,在类中,常用的有字段,构造方法,成员方法。我们的反射就是可以把一个类中所有的字段,构造方法,成员方法全部都获取出来。那么问题又来了,获取出来有什么用呢?

反射用途还是很多的,我们熟知的IDEA开发工具,他可以在我们编写代码时自动给出提示,提示我们有哪些方法可以用,有哪些构造器可以使用,它是怎么做到的呢?说到这里,不难猜出,它其实就是用的反射。

还有如下所示,我们 new 一个对象,但忘记了它可以传递哪些参数,这个时候我们按键盘上的 Ctrl + P 键,它就会自动弹出提示我们需要传递哪些参数,这个其实也使用反射做到的。

刚才我们说到了, 反射就是可以把一个类中所有的字段,构造方法,成员方法全部都获取出来。

不仅如此,通过反射我们可以获取的非常全面,非常详细,我们甚至可以获取到。

当我们获取字段(变量)时,不仅可以获取到该变量,还能获取到该变量的访问修饰符,名字,类型,并可以为它赋值或者获取初始值;

当我们获取构造方法时,不仅可以获取到构造方法,还能获取到修饰符,名字,形参,还可以创建对象;

当我们获取成员方法时,不仅可以获取到成员方法,也能获取到该方法的修饰符,名字,形参,还能获取方法的返回值,抛出的异常,以及方法上的注解也能获取到,可以说是有什么就能获取到什么,一点不剩的全都可以拿到。

此外有一点要知道,我们获取字段,构造方法,成员方法不是通过Java文件来获取的,而是通过  Class 字节码文件中获取的。

总的来说可以理解为一句话:通过反射我们可以获取到类中的所有信息。

3. 获取 Class 字节码文件对象的三种方式(重中之重,面试会问)

3.1 Class.forName("全类名")方式获取;

其实这种方式应该并不陌生,如果有小伙伴学过JDBC的,应该都大致了解过,通过Class.forName("com.mysql.jdbc.Driver")来获取该类的字节码文件对象。

下面我简单演示一下吧

如下是一个JavaBean类 Account 

package cn.itcast.user.pojo;

import java.io.Serializable;

public class Account implements Serializable {
    private static final long serialVersionUID = -421643127452356642L;
    // 账户id
    private Integer accountId;
    // 账户人名称
    private String accountName;
    // 账户密码
    private transient String accountPassword;

    public Account(Integer accountId, String accountName, String accountPassword) {
        this.accountId = accountId;
        this.accountName = accountName;
        this.accountPassword = accountPassword;
    }

    public Account() {
    }

    @Override
    public String toString() {
        return "Account{" +
                "accountId=" + accountId +
                ", accountName='" + accountName + '\'' +
                ", accountPassword='" + accountPassword + '\'' +
                '}';
    }

    public Integer getAccountId() {
        return accountId;
    }

    public void setAccountId(Integer accountId) {
        this.accountId = accountId;
    }

    public String getAccountName() {
        return accountName;
    }

    public void setAccountName(String accountName) {
        this.accountName = accountName;
    }

    public String getAccountPassword() {
        return accountPassword;
    }

    public void setAccountPassword(String accountPassword) {
        this.accountPassword = accountPassword;
    }
}

然后我定义一个 main 方法,通过 Class.forName() 的方式来获取,代码如下

public static void main(String[] args) {
        // 这里可能或出现异常,由于是 main 方法中,最好用 try。。。catch,,,捕获
        try {
            System.out.println(Class.forName("cn.itcast.user.pojo.Account"));;
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

我们直接运行此方法,就可以在控制台得到 Account 类的字节码文件对象,如下所示

3.2 类名.class 方式获取

操作方法如下代码

可以看到也没有任何问题,我就不多做解释了;

3.3 对象.getClass() 方式获取

这里必须是想要反射的类的对象,谁调用getClass,得到的就是谁的类对象。如下代码展示

还有一点可以注意一下,getClass() 方法是定义在 Obeject 类中的,所以所有的对象都可以使用此方法。

3.4 三种方式的通常应用场景

如果我想创建一个类的对象,分为以下三种阶段,每一个阶段都有它适当使用的场景。

阶段一:编写Java文件,将Java文件编写成字节码文件,这个阶段也被称为源代码阶段,可以使用 Class.forName() 的方式来获取;

阶段二:当我们把字节码文件加载到内存中准备运行的时候,可以称为加载阶段,这个阶段通常采用 类名.class 的方式获取字节码文件对象;

阶段三:在内存中运行时,我可以创建类对象,这个阶段也被称为运行阶段,通常采用 对象.getClass() 的方式获取字节码文件对象;

4. 利用反射获取构造方法

获取类的字节码文件之后,我们就可以通过字节码文件对象获取构造方法,我们可以获取单个构造器,可以获取所有构造器,还能创建对象。
如下图所示,即为获取构造方法的方法,我们简单测试一下;

如下代码,实体类 Account,我定义了多个构造器,注释如下

public class Account implements Serializable {
    private static final long serialVersionUID = -421643127452356642L;
    // 账户id
    private Integer accountId;
    // 账户人名称
    private String accountName;
    // 账户密码
    private transient String accountPassword;
    
    // 全参构造器
    public Account(Integer accountId, String accountName, String accountPassword) {
        this.accountId = accountId;
        this.accountName = accountName;
        this.accountPassword = accountPassword;
    }
    
    // 一个参数的构造器
    public Account(Integer accountId) {
        this.accountId = accountId;
    }
    
    // 两个参数的构造器
    public Account(Integer accountId, String accountName) {
        this.accountId = accountId;
        this.accountName = accountName;
    }
    
    // 无参构造器
    public Account() {
    }
}

然后我们去 main 方法中测试通过反射获取构造器,代码和注释如下

public class Test01{

    public static void main(String[] args) {
        // 需要先定义一个 Account 类的对象
        Account account = new Account();

        // 根据对象获取类的字节码文件
        Class clazz = account.getClass();


        try {
            // 获取参数类型为 Integer 的构造器
            Constructor con = clazz.getConstructor(Integer.class);

            // 打印输出该构造器
            System.out.println(con);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        System.out.println("----------------------------------------------");

        // 构造器本身也是一个对象,这里我们获取多个构造器,用列表进行接收
        Constructor[] constructors = clazz.getConstructors();

        // 输出获取到的所有构造器
        System.out.println(constructors);


    }
}

运行 main 方法,得到如下结果

在获取到类的字节码文件之后,我们不仅可以向上面那样获取到构造方法,还可以获取到更为详细的信息

在上图中可以看到,IDEA给出了大量的提示,我挑几个来说一下可以干什么

getParameterConunt() 获取参数个数;

getParameterTypes()  获取参数类型;

getParameter() 获取所有参数;

getModifiers() 获取该方法的权限修饰符,如 public,private,但返回的值是整数,如果返回1,则说明为public,若返回2,则为private。

看他们的英文名字就能大概了解了,我们的IDEA自动提示功能就是通过这些功能来做到的!

5. 利用反射获取属性

利用反射我们也可以获取到类中的属性,例如刚才的 Account 类,我们可以获取到它的 账户id,账户名称,账户密码等属性,相应方法如下所示

 我们还是需要先获取类的字节码文件,再通过字节码文件的方法获取类中的属性,如下所示

我这里是获取所有的,当然也可以获取单个的,将方法的后缀 s 去掉就可调用获取单个属性的方法,它也和刚才的构造方法一样,可以获取属性的修饰符,还可以获取到属性的变量名,这里就不重复演示了。 

6. 通过反射获取成员方法

如下图中所示的即为获取成员方法的方法,我们也是要通过字节码文件对象来获取

  我们把刚才的 Account 类添加上 get和set方法

通过字节码文件即可获取 get 和 set 方法

还有几个方法我就不一一展示了,也都不难。

其实反射这一章在开发时并不常用,他们主要是应用与框架,如果以后你自己也开发框架的话,会经常用到反射。

另外,获取Class字节码文件的三种方法是面试时常常问到的一个点,各位需要好好记住。

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

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

相关文章

prometheus监控k8s kube-proxy target down

prometheus target down 修改配置 kubectl edit cm/kube-proxy -n kube-systemmetricsBindAddress: "0.0.0.0:10249"删除 kube-proxy pod 使之重启应用配置 kubectl delete pod --force kubectl get pod -n kube-system |grep kube-proxy|awk {print $1} -n kube-…

网工内推 | 网络安全工程师,最高15K,有高温补贴

01 超圣信华 招聘岗位:网络安全工程师 职责描述: 1. 负责网络安全产品的售前沟通交流、现状调研、方案设计、产品测试、产品选型和招投标等工作。 2. 负责网络安全集成项目的实施管理、项目交付文档编制以及项目验收等工作。 3. 负责网络安全产品的售后…

十八、Spring6集成MyBatis3.5

目录 十八、Spring6集成MyBatis3.5 18.1 实现步骤 18.2 具体实现 第一步:准备数据库表 第二步:IDEA中创建一个模块,并引入依赖 第三步:基于三层架构实现,所以提前创建好所有的包 第四步:编写pojo 第…

算法入门篇——用位运算解决一些问题

目录 1.判断一个数是2的次方数 2.统计一个数,它的二进制数中,1的个数 3.在2*(n-1)个数中,找到只出现一次的那个数 1.判断一个数是2的次方数 这个问题有好几种做法,但是最优雅的解法是用’位运算‘来做。…

【Spring Cloud 三】Eureka服务注册与服务发现

系列文章目录 【Spring Cloud一】微服务基本知识 Eureka服务注册与服务发现 系列文章目录前言一、什么是Eureka?二、为什么要有服务注册发现中心?三、Eureka的特性四、搭建Eureka单机版4.1Eureka服务端项目代码pom文件配置文件启动类启动项目查看效果 E…

深入学习Mysql引擎InnoDB、MylSAM

目录 一、什么是MySQL 二、什么是InnoDB 三、什么是MyISAM 四、MySQL不同引擎有什么区别 一、什么是MySQL MySQL是一种广泛使用的开源关系型数据库管理系统(RDBMS),它是由瑞典MySQL AB公司开发并推广,后来被Sun Microsystems收…

FPGA项目设计:数字时钟

项目要求: 设计一个数字时钟,数码管前两位显示小时,数码管中间两位显示分钟,数码管后面两位显示秒。 项目设计: 系统框架图: 计数模块时序图: 代码实现: 计数模块: /…

走进人工智能|自动驾驶 开启智能出行新时代

前言 自动驾驶,也被称为无人驾驶或自动驾驶汽车,是指能够在没有人类干预的情况下自主地感知环境、决策和控制车辆行驶的技术和系统。 文章目录 前言主题发展趋势自动驾驶等级L0级自动驾驶L1级别自动驾驶L2级别自动驾驶L3级别自动驾驶L4级别自动驾驶L5级…

C# Microsoft消息队列服务器的使用 MSMQ

先安装消息队列服务器 private static readonly string path ".\\Private$\\myQueue";private void Create(){if (!MessageQueue.Exists(path)){MessageQueue.Create(path);}}private void Send(){Stopwatch stopwatch new Stopwatch();stopwatch.Start();Message…

em3288 linux_4.19 lvds+tp调试

一、显示配置\rk3288_linux4.19\kernel\arch\arm\boot\dts\rk3288-evb-act8846.dtspanel {compatible "simple-panel";backlight <&backlight>;bus-format <MEDIA_BUS_FMT_RGB666_1X18>;enable-gpios <&gpio1 24 GPIO_ACTIVE_HIGH>;ena…

2023年中职组“网络安全”赛项吉安市竞赛任务书

2023年中职组“网络安全”赛项 吉安市竞赛任务书 一、竞赛时间 总计&#xff1a;360分钟 竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 A模块 A-1 登录安全加固 180分钟 200分 A-2 本地安全策略配置 A-3 流量完整性保护 A-4 事件监控 A-5 服务加固…

基于Java的房屋租赁系统设计与实现(源码+lun文+数据库)

对于需要租房的人&#xff0c;有的可能没有时间去街上广告处查看房屋信息&#xff1b;对于房屋出租者来说&#xff0c;大量复杂的房产信息、租金等信息很难通过传统的方式进行管理。以方便租客租房&#xff0c;房东求租、求售的需求为向导&#xff0c;开发一套基于web的房屋管理…

数字图像处理-彩色图像处理

文章目录 一、彩色模型1.1RGB彩色模型1.2CMY和CMYK彩色模型1.3HSI彩色模型 二、伪彩色图像处理2.1灰度分层2.2灰度到彩色的变换 三、彩色图像的分割3.1RGB中的彩色图像分割3.2彩色边缘检测 一、彩色模型 1.1RGB彩色模型 RGB空间是生活中最常用的一个模型&#xff0c;电视机、…

2D视觉检测算法整理

1.ROI pooling 和 ROI align的区别 ROI pooling第一步根据候选区域找特征图的位置&#xff0c;可能不是刚好对应&#xff0c;需要一次量化&#xff0c;如上图所示&#xff0c;第二次是特征图需要转化为特定的大小&#xff0c;这时候pooling可能也不能正好整除&#xff0c;所以第…

Vue3状态管理库Pinia——实现简易版购物车

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

重排序问题(详细说明指令重排序)

在执行程序时&#xff0c;为了提高性能&#xff0c;编译器和处理器常常会对指令做重排序。 重排序分3种类型。 编译器优化的重排序。编译器在不改变单线程程序语义的前提下&#xff0c;可以重新安排语句的执行顺序。 指令级并行的重排序。现代处理器采用了指令级并行技术&…

MySQL主从复制原理以及实操

一、MySQL主从复制原理&#xff1a; 1、MySQL将数据变化记录到二进制日志中&#xff1b; 2、Slave将MySQL的二进制日志拷贝到Slave的中继日志中&#xff1b; 3、Slave将中继日志中的事件在做一次&#xff0c;将数据变化&#xff0c;反应到自身&#xff08;Slave&#xff09;的数…

在Geogle Drive 上面下载压缩的文件

需要使用到 OCC3D 上面 的Waymo Occupancy 真值。 Occ3d 应该是一个文件夹里面有很多 个压缩包&#xff0c;如果直接下载 会下载很多个文件。 双击点进去 选择好对应的序列再进行下载。 这里的 000 001 应该是对应的 waymo 的相机序列。 waymo 的相机序列也是798 个序列

【数据结构】常见的排序算法

常见的排序算法 常见的排序算法插入排序之直接插入排序时间复杂度特性总结 插入排序之希尔排序时间复杂度 选择排序之直接选择排序特性总结 选择排序之堆排序时间复杂度特性总结 交换排序之冒泡排序特性总结 交换排序之快速排序hoare版本挖坑法双指针法快速排序的优化1&#xf…

(YouTube)KDBA QML 学习笔记1

&#xff08;YouTube&#xff09;KDBA QML 学习笔记 旧版本(QML文件介绍) main.qml import QtQuick 2.0Text {text: "Hell World" }main.cpp #include <QtQuick>int mian(int argc, char *argn[]) {QGuiApplication app(argc, argv);//QT开始 QQuickvi…