2023.12.12 关于 Java 反射详解

目录

基本概念

定义

用途

反射相关的类

反射基本原理

Class 类中的相关方法

常用获得类相关的方法

常用获得类中属性相关的方法

常用获得类中构造器相关的方法

常用获得类中方法相关的方法

实例理解

反射优缺点


基本概念

定义

  • Java 的反射(reflection)机制是一种强大功能,它可以让我们在运行时动态地获取和操作 类 或 对象 的信息

实例理解

  • 我们可以通过反射机制来创建一个类的对象,而不需要使用 new 关键字
  • 我们也可以通过反射机制来访问或修改一个对象的私有属性或方法,而不需要遵循封装原则
  • 我们还可以通过反射机制来调用一个对象的任意方法,而不需要知道它的参数类型或返回值类型

用途

典型用途一:

  • 在开发第三方应用时,我们可能会遇到一些类的成员变量、方法或属性是私有的,或者只对系统应用开放,这就意味着我们不能直接访问这些成员或方法
  • 这时我们便可以在运行时 通过 Java 的反射机制 来动态地访问和操作类的内部成员,包括私有成员和方法

典型用途二:

  • 反射在开发通用框架 Spring 中起着重要的作用
  • 在Spring 框架中,所有类(Bean)都由 Spring 容器进行管理,这些 Bean 可以通过 XML 配置或注解来配置
  • 当我们从容器中获取Bean 以进行依赖注入时,容器会读取配置信息,这些配置信息包含了类的信息,比如类的名称、属性、方法等
  • Spring根据这些信息 动态地创建这些类的实例,这个过程就是所谓的 依赖注入,该过程中,反射起到了关键作用
  • Spring 使用反射来动态地创建类的实例,调用方法,以及设置属性值

反射相关的类

反射基本原理

  • Java 的反射机制是基于 java.lang.Class 类实现的
  • 当我们编译一个 Java 文件时,会生成一个 .class 文件
  • 当 JVM 加载这个 .class 文件时,会将其解析为一个 java.lang.Class 类的对象
  • 在程序运行时,每个 Java 文件都会被 JVM 解析为一个 Class 类的实例
  • 这个 Class 类的实例包含了该 Java 文件中所定义类的所有信息,包括类的名称、属性、方法等
  • 我们可以通过 Java 的反射机制来操作这个 Class 类的实例
  • 具体来说,我们可以使用反射来获取类的属性和方法,甚至可以添加或修改类的属性和方法
  • 这使得我们可以在运行时动态地操作类,使其成为一个 动态的类
类名用途
Class 类代表类的实体,在运行的 Java 应用程序中表示类和接口
Field 类代表类的成员变量、类的属性
Method 类代表类的方法
Constructor 类代表类的构造方法

Class 类中的相关方法

常用获得类相关的方法

方法用途
getClassLoader()获得类的加载器
getDeclaredClasses()返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的)
forName(String className)根据类名返回类的对象
newInstance()创建类的实例
getName()获得类的完整路径名字

常用获得类中属性相关的方法

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

常用获得类中构造器相关的方法

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

常用获得类中方法相关的方法

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

实例理解

  • 此处我们先创建一个 Student 类
class Student{//私有属性nameprivate String name = "master";//公有属性agepublic int age = 18;//不带参数的构造方法public Student(){System.out.println("Student()");}private Student(String name,int age) {this.name = name;this.age = age;System.out.println("Student(String,name)");}private void eat(){System.out.println("make hamburger!");}public void sleep(){System.out.println("go to bed!");}private void function(String str) {System.out.println(str);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
  • 此处介绍三种方式来获取 Student 的 Class 对象

public class Demo1 {public static void main(String[] args) {
//        有三种方式可以获取 Class 对象Student student1 = new Student();
//        1、通过对象的 getClass() 方法Class<?> c1 = student1.getClass();
//        2、通过类名 .class 获取Class<?> c2 = Student.class;
//        3、通过调用 Class.forName() 方法获取了 Student 类的 Class 对象
//        Class.forName() 方法需要一个类的全限定名(包括 包名和类名) 作为参数
//        此处的 ? 是一个通配符,用于表示未知类型
//        当我们声明一个泛型变量时,如果我们不确定或不关心实际的类型参数,我们可以使用 ? 来表示Class<?> c3 = null;try {c3 = Class.forName("Student");} catch (ClassNotFoundException e) {throw new RuntimeException(e);}
//        此处证明通过上述三种方式所获取的 Class 对象 都是同一个System.out.println((c1.equals(c2) && c1.equals(c3) && c2.equals(c3)) ? "true" : "false");}
}
  • 此处我们通过反射机制创建一个对象

import java.lang.reflect.InvocationTargetException;public class ReflectClassDemo {//  通过反射创建一个对象public static void reflectNewInstance() throws InstantiationException, IllegalAccessException, ClassNotFoundException {Class<?> c3 = Class.forName("Student");
//        通过调用 Class 类的 newInstance() 方法来创建一个 c3 对应类的新实例
//        newInstance() 方法调用的是这个类的无参构造函数
//        如果这个类没有无参构造函数,或者无参构造函数是私有的,那么 newInstance 会抛出一个异常
//        因为 newInstance() 方法返回的类型为 Object 类 所以需要类型转换,此处转换为 Student 类Student student = (Student) c3.newInstance();System.out.println(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectNewInstance();}
}

运行结果:

  • 此处我们通过反射机制获取私有的构造方法
import java.lang.reflect.Constructor;public class ReflectClassDemo {//  通过反射获取私有的构造方法public static void  reflectPrivateConstructor() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {Class<?> c3 = Class.forName("Student");Constructor<?> constructor = c3.getDeclaredConstructor(String.class,int.class);
//        注意只要是涉及到 private 都要使用 setAccessible(true) 来打开权限,此处的构造方法为私有的constructor.setAccessible(true);
//        此处利用构造方法 修改年龄和性别Student student = (Student)constructor.newInstance("xiaolin",20);System.out.println(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectPrivateConstructor();}
}

运行结果:

  • 此处我们通过反射机制获取私有属性
import java.lang.reflect.Field;public class ReflectClassDemo {//  通过反射获取私有属性public static void reflectPrivateField() throws ClassNotFoundException, NoSuchFieldException, InstantiationException, IllegalAccessException {Class<?> c3 = Class.forName("Student");Field field = c3.getDeclaredField("name");
//        注意只要是涉及到 private 都要使用 setAccessible(true) 来打开权限,此处的 name 属性是私有的field.setAccessible(true);Student student = (Student) c3.newInstance();
//        此处修改私有属性field.set(student,"haoran");System.out.println(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectPrivateField();}
}

运行结果:

  • 此处我们通过反射机制获取私有方法
import java.lang.reflect.Method;public class ReflectClassDemo {//  通过反射获取私有方法public static void reflectPrivateMethod() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {Class<?> c3 = Class.forName("Student");Method method1 = c3.getDeclaredMethod("function", String.class);Method method2 = c3.getDeclaredMethod("sleep");
//        注意只要是涉及到 private 都要使用 setAccessible(true) 来打开权限,此处的 function 方法是私有的method1.setAccessible(true);Student student = (Student) c3.newInstance();
//        此处给 function 方法传参method1.invoke(student,"此处利用反射机制给 function 方法传个字符串参数");
//        此处调用 sleep 方法,该方法为 public 无需额外打开权限,直接调用即可method2.invoke(student);}public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, NoSuchFieldException {reflectPrivateMethod();}
}

运行结果:

反射优缺点

优点

  • 对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个类都能调用它的任意一个方法
  • 增加程序的灵活性和扩展性,降低耦合性,提高自适应性
  • 反射已经运用在很多流行框架,典型代表为 Spring

缺点

  • 使用反射会有效率问题,会导致程序效率降低
  • 反射技术绕过了源代码的技术,因而会带来维护问题
  • 反射代码比相应的直接代码更复杂

总结:

  • 虽然反射非常强大,但也需要谨慎使用
  • 我们需要在反射带来的灵活性和可扩展性与其带来的性能开销、维护问题和代码复杂性之间找到一个平衡
  • 某些情况下,比如开发通用的框架,使用反射式非常有价值的
  • 但在其他情况下,我们可能更倾向于使用更简单、更直接的代码

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

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

相关文章

算法笔记—链表、队列和栈

链表、队列和栈 1. 链表1.1 单链表反转1.2 双链表反转1.3 合并两个有序链表1.4 链表相加1.5 划分链表 2. 队列和栈2.1 循环队列2.2 栈实现队列2.3 队列实现栈2.4 最小栈2.2 双端队列 1. 链表 1.1 单链表反转 力扣 反转链表 // 反转单链表public ListNode reverseList(ListNod…

【RTOS学习】模拟实现任务切换 | 寄存器和栈的变化

&#x1f431;作者&#xff1a;一只大喵咪1201 &#x1f431;专栏&#xff1a;《RTOS学习》 &#x1f525;格言&#xff1a;你只管努力&#xff0c;剩下的交给时间&#xff01; 目录 &#x1f3c0;认识任务切换&#x1f3d0;切换的实质&#x1f3d0;栈中的内容&#x1f3d0;切…

基于ssm的前后端分离鲜花销售系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本鲜花销售系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&am…

java中的包

1.包的本质分析(原理) 包的本质 实际上就是创建不同的文件夹来保存类文件 2.一个文件中有两个类的i情况 package com.use;import com.xiaoqiang.Dog;public class Test {public static void main(String[] args) {Dog dog new Dog();System.out.println(dog); //com.xiaoqian…

最新版ES8的client API操作 Elasticsearch Java API client 8.0

作者&#xff1a;ChenZhen 本人不常看网站消息&#xff0c;有问题通过下面的方式联系&#xff1a; 邮箱&#xff1a;1583296383qq.comvx: ChenZhen_7 我的个人博客地址&#xff1a;https://www.chenzhen.space/&#x1f310; 版权&#xff1a;本文为博主的原创文章&#xff…

“京东API接口技术大揭秘:让你轻松驾驭电商开发!“

京东平台API接口技术贴 一、概述 京东平台提供了丰富的API接口&#xff0c;方便开发者进行应用开发。这些API接口涵盖了商品信息、订单管理、用户认证等多个方面&#xff0c;为开发者提供了强大的支持。本文将详细介绍京东平台API接口的技术细节和使用方法。 二、API接口概述…

回归预测 | MATLAB实现CHOA-BiLSTM黑猩猩优化算法优化双向长短期记忆网络回归预测 (多指标,多图)

回归预测 | MATLAB实现CHOA-BiLSTM黑猩猩优化算法优化双向长短期记忆网络回归预测 &#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现CHOA-BiLSTM黑猩猩优化算法优化双向长短期记忆网络回归预测 &#xff08;多指标&#xff0c;多图&#xff09;效果…

CMake是什么

文章目录 一.什么是CMake二.CMake安装三.CMake一个HelloWord-的语法介绍3.1 PROJECT关键字3.2 SET关键字3.3 MESSAGE关键字3.4 ADD_EXECUTABLE关键字3.5 include_directories关键字3.6 aux_source_directory 四.语法的基本原则4.1 语法注意事项 五.内部构建和外部构建5.1 外部构…

dialog 在xml文件进行了自适应宽,但是失效了

如下图 讲述了为什么已经设置好了dialog的宽高 到了显示的时候就会失效的原因 解决方式 &#xff1a; 在自定的dialog中的onstart()方法中进行重新设置宽高 Window window getWindow();WindowManager.LayoutParams lp window.getAttributes();lp.height LinearLayout.La…

【操作系统的IO模型有哪些?】

操作系统的IO模型有哪些&#xff1f; 操作系统中的IO模型逐一拓展同步阻塞IO模型同步非阻塞IO模型IO复用模型信号驱动IO模型异步IO模型 操作系统中的IO模型 为了保护操作系统的安全&#xff0c;通过缓存加快系统读写&#xff0c;会将内存分为用户空间和内存空间两个部分。如果…

想学精MySQL,得先捋一捋高可用架构

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…

ARM day8

1.题目&#xff1a;主机获取从机里面的温湿度数据&#xff0c;并打印出来 结果&#xff1a; 代码&#xff1a; main.c #include "iic.h"#include "si7006.h"void delay(int ms){int i,j;for(i0;i<ms;i){for(j0;j<2000;j);}}int main(){short tem;…

关于“Python”的核心知识点整理大全11

目录 ​编辑 6.2.4 修改字典中的值 6.2.5 删除键—值对 注意 删除的键—值对永远消失了。 6.2.6 由类似对象组成的字典 6.3 遍历字典 6.3.1 遍历所有的键—值对 6.3.2 遍历字典中的所有键 往期快速传送门&#x1f446;&#xff08;在文章最后&#xff09;&#xff1a; 6.…

【网络编程之初出茅庐】

前言&#xff1a;本章主要先讲解一些基本的网络知识&#xff0c;先把基本的知识用起来&#xff0c;后续会更深入的讲解底层原理。 网络编程的概念 网络编程&#xff0c;指网络上的主机&#xff0c;通过不同的进程&#xff0c;以编程的方式实现网络通信&#xff08;或称为网络数…

网络基础(九):VLAN的概述及配置

目录 前言 一、分割广播域的方法 二、VLAN 1、VLAN的概述及优势 1.1VLAN的概述 1.2VLAN的优势 2、VLAN的种类 3、VLAN的三种端口类型 4、VLAN 的工作原理 4.1VLAN数据帧 4.2VLAN的范围 4.2VLAN的access类型工作原理 4.3VLAN的trunk类型工作原理 4.4VLAN的Hybird类…

CentOS7安装MySQL8.0

一、使用Yum安装 1. 使用wget下载MySQL的rpm包 wget https://repo.mysql.com//mysql80-community-release-el7-3.noarch.rpm2. 安装下载好的rpm包 yum localinstall mysql80-community-release-el7-3.noarch.rpm 3. 安装mysql&#xff08;该步可能出现问题&#xff09; yum…

JAVAEE-8-线程池

池 我们之前也接触过,比如说常量池,数据库连接池,线程池,进程池,内存池等等, 池的共性: 1.提前把要用的对象准备好 2.把用完的对象也不要立即释放,先留着以备下次使用 来提高效率!!! 最开始,进程能够解决并发编程的问题,因为频繁创建销毁进程的开销成本太大了,所以我们引…

新版Spring Security6.2案例 - Basic HTTP Authentication

前言&#xff1a; 书接上文&#xff0c;翻译官网Authentication的Username/Password这页&#xff0c;接下来继续翻译basic的这页&#xff0c;因为官网说的都是原理性的&#xff0c;这边一个小案例关于basic http authentication。 Basic Authentication 本节介绍 HTTP 基本身…

Unity 通过鼠标控制模拟人物移动和旋转视角

要通过鼠标控制并模拟人物移动和转换视角&#xff0c;将会使用射线检测、鼠标点击和鼠标水平移动&#xff0c;配合物体旋转和移动方法共同实现。 首先搭建个由一个Plane地板和若干cube组成的简单场景&#xff1a; 其次创建一个Capsule作为移动物体&#xff0c;并把摄像头拉到该…

腾讯云优惠券领取指南

腾讯云优惠券是降低云服务成本的有效手段&#xff0c;无论是新用户还是老用户&#xff0c;都可以通过下面方法领取到适合自己的优惠券。 1、腾讯云优惠券领取 领取入口&#xff1a;txy.ink 2、腾讯云优惠券介绍 腾讯云优惠券包括代金券和折扣券&#xff0c;代金券可以在结算…