Java反射详解:入门+使用+原理+应用场景

反射非常强大和有用,现在市面上绝大部分框架(spring、mybatis、rocketmq等等)中都有反射的影子,反射机制在框架设计中占有举足轻重的作用。

所以,在你Java进阶的道路上,你需要掌握好反射。

怎么才能学好反射,我们需要弄懂以下几个问题:

1.反射是什么?

2.反射有什么用?

3.反射的实现原理?

4.怎么用反射?

下面我就针对以上的疑问,一一来讲解。

反射是什么?

反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。

反射是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意方法和属性,这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

一句话总结:反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。

为什么要用反射?

Java Reflection功能非常强大,并且非常有用,比如:

  • 获取任意类的名称、package信息、所有属性、方法、注解、类型、类加载器等
  • 获取任意对象的属性,并且能改变对象的属性
  • 调用任意对象的方法
  • 判断任意一个对象所属的类
  • 实例化任意一个类的对象
  • 通过反射我们可以实现动态装配,降低代码的耦合度,动态代理等。

怎么使用反射?

一般情况下我们通过反射创建类对象主要有两种方式:

  • 通过 Class 对象的 newInstance() 方法
  • 通过 Constructor 对象的 newInstance() 方法

第一种:通过 Class 对象的 newInstance() 方法。

Class clz = Class.forName("com.lxx.reflection.Hello");
Hello hello= (Hello)clz.newInstance();

第二种:通过 Constructor 对象的 newInstance() 方法

Class clz = Class.forName("com.lxx.reflection.Hello");
Constructor constructor = clz.getConstructor();
Hello hello= (Hello)clz.newInstance();

通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法,下面的代码就调用了一个有参数的构造方法进行了类对象的初始化。

Class clz = Class.forName("com.lxx.reflection.Hello");
Constructor constructor = clz.getConstructor(String.class);
Hello hello= (Hello)clz.newInstance("hello world");

接下来我们就可以通过具体的API调用获取到详细的属性或者方法等详细了。

1、获取类的成员变量的信息

Field[] fields = cls.getDeclaredFields();

更加详细成员变量获取参考如下:

方法用途
getField(String name)获取某个公有的属性对象
getFields()获取所有公有的属性对象
getDeclaredField(String name)获取某个属性对象(public和非public)
getDeclaredFields()获取所有属性对象(public和非public)

2、获得类方法

Method[] methods = cls.getDeclaredMethods();

更加详细方法获取参考如下:

方法用途
getMethod(String name,Class…<?> parameterTypes)获取该类某个公有的方法
getMethods()获取该类所有公有的方法
getDeclaredMethod(String name,Class…<?> parameterTypes)获取该类某个方法(public和非public)
getDeclaredMethods()获取该类所有方法(public和非public)

3、获得构造函数

Constructor[] constructors = cls.getDeclaredConstructors();

更加详细方法获取参考如下:

方法用途
getConstructor(Class…<?> parameterTypes)获取该类中与参数类型匹配的公有构造方法
getConstructors()获取该类中所有公有构造方法
getDeclaredConstructor(Class…<?> parameterTypes)获取该类中与参数类型匹配的构造方法
getDeclaredConstructors()获取该类所有构造方法

通过以上一个小案例了解了反射的使用,但如果你想对反射掌握得更好,还需深入理解反射背后的底层实现原理。

反射工作原理?

调用反射的总体流程如下:

1、当我们编写完一个Java项目之后,每个java文件都会被编译成一个.class文件。

在这里插入图片描述

2、这些class文件在程序运行时会被ClassLoader加载到JVM中,当一个类被加载以后,JVM就会在内存中自动产生一个Class对象。

在这里插入图片描述

3、通过Class对象获取Field/Method/Construcor

在这里插入图片描述

我们一般平时是通过new的形式创建对象实际上就是通过这些Class来创建的,只不过这个class文件是编译的时候就生成的,程序相当于写死了给jvm去跑。

在这里插入图片描述

反射是什么呢?当我们的程序在运行时,需要动态的加载一些类,这些类可能之前用不到所以不用加载到jvm,而是在运行时根据需要才加载。

原来使用new的时候,需要明确的指定类名,这个时候属于硬编码实现,而在使用反射的时候,可以只传入类名参数,就可以生成对象,降低了耦合性,使得程序更具灵活性。

反射的应用场景

在这里插入图片描述

举个例子我们的项目底层数据库有时是用mysql,有时用oracle,需要动态地根据实际情况加载驱动类,这个时候反射就有用了,假设 com.lxx.java.myqlConnection,com.lxx.java.oracleConnection这两个类我们要用。

这时候我们在使用 JDBC 连接数据库时使用 Class.forName()通过反射加载数据库的驱动程序,如果是mysql则传入mysql的驱动类,而如果是oracle则传入的参数就变成另一个了。

Spring 框架的 IOC(动态加载管理 Bean),Spring通过配置文件配置各种各样的bean,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载,你的程序就能健壮地运行。

还有Spring AOP(动态代理)功能都和反射有关系。

除此之外还有很多框架:mybatis、dubbo、rocketmq等等都会用到反射机制。

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

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

相关文章

LeetCode | 876. 链表的中间结点

LeetCode | 876. 链表的中间结点 OJ链接 我们这里有一个很好的思路&#xff0c;我们定义两个变量&#xff0c;第一个变量走两步&#xff0c;第二个变量走一步&#xff0c;一直循环&#xff0c;当第一个变量走到最后的时候停下来&#xff0c;这个时候第二个变量就是中间的那个…

【Apache Flink】Flink DataStream API的基本使用

Flink DataStream API的基本使用 文章目录 前言1. 基本使用方法2. 核心示例代码3. 完成工程代码pom.xmlWordCountExample测试验证 4. Stream 执行环境5. 参考文档 前言 Flink DataStream API主要用于处理无界和有界数据流 。 无界数据流是一个持续生成数据的数据源&#xff0…

unraid 安装并设置 zerotier 内网穿透安装 unraid 局域网内其他设备

Read Original 最近看了以下两个文章&#xff0c;感谢发布的各种精彩文章&#xff0c;让我受益匪浅。OPENWRT 的固件在设置了&#xff0c;【自动允许客户端 NAT】后&#xff0c;可以直接访问局域网其他设备&#xff0c;而我 unraid 部署 zerotier 后&#xff0c;只能访问 unra…

API接口安全设计

简介 HTTP接口是互联网各系统之间对接的重要方式之一&#xff0c;使用HTTP接口开发和调用都很方便&#xff0c;也是被大量采用的方式&#xff0c;它可以让不同系统之间实现数据的交换和共享。 由于HTTP接口开放在互联网上&#xff0c;所以我们就需要有一定的安全措施来保证接口…

C++异常处理

C 异常处理涉及到三个关键字&#xff1a;try、catch、throw。 在 c程序中&#xff0c;任何需要检测异常的语句&#xff0c;都必须在 try 语句块中执行&#xff0c;异常必须由紧跟着 try 语句后面的 catch 语句来捕获并处理&#xff0c;因此 try 与 catch 总是结合使用&#xff…

C++并发编程实战——05.内存模型与原子操作

文章目录 内存模型与原子操作内存模型原子操作和原子类型标准原子类型std::atomic_flagstd::atomic\<bool>std::atomic<T\*>std::atomic<user_define_type> 类模板非成员函数 同步操作和强制排序同步发生与先行发生内存序**顺序一致性**(memory_order_seq_cs…

图解系列--路由器和它庞大的功能

03.01 何为路由器 路由器是指主要负责 OSI参考模型中网络层的处理工作&#xff0c;并根据路由表信息在不同的网络 之间转发IP 分组的网络硬件(图3-1)。这里的网络一般是指IP 子网&#xff0c;也可以称为广播域。此外&#xff0c;现在的路由器还会搭载其他各种各样的功能。 0…

【Midjourney入门教程3】写好prompt常用的参数

文章目录 1、图片描述词&#xff08;图片链接&#xff09;文字描述词后缀参数2、权重划分3、后缀参数版本选择&#xff1a;--v版本风格&#xff1a;--style长宽比&#xff1a;--ar多样性: --c二次元化&#xff1a;--niji排除内容&#xff1a;--no--stylize--seed--tile、--q 4、…

openeuler 使用指令查找U盘:输入fdisk -l,内核崩溃 ,系统重启,使用lsblk显示正常,数据传输正常

报错日志&#xff1a; [rootedgenode1 ~]# fdisk -l Disk /dev/ram0: 4 MiB, 4194304 bytes, 8192 sectors Units: sectors of 1 * 512 512 bytes Sector size (logical/physical): 512 bytes / 4096 bytes I/O size (minimum/optimal): 4096 bytes / 4096 bytes Disk /d…

数据结构与算法:使用数组模拟队列Java版

逻辑分析 代码实现 package com.haimeng.queue;import java.util.Scanner;public class ArrayQueueDemo {public static void main(String[] args) {//测试一把//创建一个队列ArrayQueue queue new ArrayQueue(3);char key ; //接收用户输入Scanner scanner new Scanner(S…

web3 在React dapp中全局管理web3当前登录用户/智能合约等信息

上文 Web3 React项目Dapp获取智能合约对象我们在自己的前端dapp项目中链接获取到了 自己的智能合约 我们继续 我们还是先启动ganache环境 终端输入 ganache -d然后发布一下我们的智能合约 打开我们的合约项目 终端输入 truffle migrate --reset这样 我们的智能合约就部署到区…

L1和L2正则化通俗理解

机器学习中&#xff0c;如果参数过多&#xff0c;模型过于复杂&#xff0c;容易造成过拟合&#xff08;overfit&#xff09;。即模型在训练样本数据上表现的很好&#xff0c;但在实际测试样本上表现的较差&#xff0c;不具备良好的泛化能力。为了避免过拟合&#xff0c;最常用的…