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{
    //私有属性name
    private String name = "master";
    //公有属性age
    public 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);
    }
    @Override
    public 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

缺点

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

总结:

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

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…

达索系统SOLIDWORKS 2024 Visualize新功能

SOLIDWORKS Visualize&#xff08;原名为 Bunkspeed&#xff09;是一整套独立的软件工具&#xff0c;Visualize模块主要是用于对SOLIDWORKS设计出的产品图进行渲染、做动画&#xff0c;方便用户更好的展示、宣传产品&#xff1b;以最快速、最轻松的方式创建专业的照片级图像、动…

汽车差速器市场分析:预计2029年将达到218亿元

差速器是为了调整左右轮的转速差而装置的。在四轮驱动时&#xff0c;为了驱动四个车轮&#xff0c;必须将所有的车轮连接起来&#xff0c;如果将四个车轮机械连接在一起&#xff0c;汽车在曲线行驶的时候就不能以相同的速度旋转&#xff0c;为了能让汽车曲线行驶旋转速度基本一…

智能优化算法应用:基于生物地理学算法3D无线传感器网络(WSN)覆盖优化 - 附代码

智能优化算法应用&#xff1a;基于生物地理学算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用&#xff1a;基于生物地理学算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.生物地理学算法4.实验参数设定5.算法…

2023年12月14日 十二生肖 今日运势

小运播报&#xff1a;2023年12月14日&#xff0c;星期四&#xff0c;农历十一月初二 &#xff08;癸卯年甲子月丙午日&#xff09;&#xff0c;法定工作日。 红榜生肖&#xff1a;羊、狗、虎 需要注意&#xff1a;牛、马、鼠 喜神方位&#xff1a;西南方 财神方位&#xff…

静态SOCKS5的未来发展趋势和新兴应用场景

随着网络技术的不断发展和进步&#xff0c;静态SOCKS5代理也在不断地完善和发展。未来&#xff0c;静态SOCKS5代理将会呈现以下发展趋势和新兴应用场景。 一、发展趋势 安全性更高&#xff1a;随着网络安全问题的日益突出&#xff0c;用户对代理服务器的安全性要求也越来越高…

2-分布式存储之glusterfs

任务背景 实现了远程的存储共享(NAS或SAN)后, 公司业务发展迅速, 存储空间还需要增大。使用NAS或SAN都不方便扩容&#xff0c;NAS可以增加新的挂载目录, SAN可以增加新的硬盘&#xff0c;但我们希望直接在原来挂载的业务目录上实现在线扩容&#xff0c;数据体量越来越大, 这个…

TypeScript中的基本类型

提示&#xff1a;TypeScript中的基本类型 文章目录 前言基本类型1.类型声明2.自动类型判断3.类型断言 前言 TypeScript &#xff08;计算机编程语言&#xff09;简称&#xff1a;TS&#xff0c;是 JavaScript 的超集。简单来说就是&#xff1a;JS 有的 TS 都有。JS写的代码在TS…

UDP分片与丢包,UDP真的比TCP高效吗?

一、UDP 报文格式 每个 UDP 报文分为 UDP 报头和 UDP 数据区两部分。报头由 4 个 16 位长&#xff08;2 字节&#xff09;字段组成&#xff0c;分别说明该报文的源端口、目的端口、报文长度和校验值。 UDP 报文格式如图所示。 UDP 报文中每个字段的含义如下&#xff1a; 源端…

linux下time与dd命令结合测试存储器速度

在Linux中&#xff0c;"time"和"dd"命令是两个独立的命令&#xff0c;它们可以结合使用来测量"dd"命令执行的时间。 下面是它们的简要说明&#xff1a; time命令&#xff1a; "time"命令用于测量命令执行的时间和资源使用情况。它可以…

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

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

自动反冲洗过滤器直通式工作原理介绍和附反冲洗原理图动画讲解

​ 1&#xff1a;自动反冲洗过滤器直通式设备介绍 自动反冲洗过滤器是一种先进、高效且易操作的精密设备&#xff0c;广泛应用于冶金、化工、石油、造纸、医药、食品、采矿、电力、城市给水等领域。 在过滤过程中&#xff0c;待过滤的水由进水口进入过滤器机体&#xff0c;流…

beanshell、jcef

BeanShell BeanShell是一个小型嵌入式Java源代码解释器&#xff0c;具有对象脚本语言特性&#xff0c;能够动态地执行标准JAVA语法。 BeanShell不仅仅可以通过运行其内部的脚本来处理Java应用程序&#xff0c;还可以在运行过程中动态执行你java应用程序执行java代码。因为Bea…

C/C++ 表达式求值(含多位数)

个人主页&#xff1a;仍有未知等待探索_C语言疑难,数据结构,算法-CSDN博客 专题分栏&#xff1a;算法_仍有未知等待探索的博客-CSDN博客 目录 一、前言 二、解析 分析 最后直接上代码&#xff01; 一、前言 表达式求值是一个比较基础的代码关于栈的使用。在写的时候充分锻炼…

Kubernetes版本升级到v1.18.0方法

升级k8s版本才能使用kube-prometheus安装监控 1、查看集群状态 [rootk8s-master k8s-script]# kubectl get nodes NAME STATUS ROLES AGE VERSION k8s-master Ready master 5d22h v1.18.0 k8s-slave1 Ready <none> 4d10h v1.18.0 k…

js Array.every()的使用

2023.12.13今天我学习了如何使用Array.every()的使用&#xff0c;这个方法是用于检测数组中所有存在的元素。 比如我们需要判断这个数组里面的全部元素是否都包含张三&#xff0c;可以这样写&#xff1a; let demo [{id: 1, name: 张三}, {id: 2, name: 张三五}, {id: 3, name…

物奇平台MIC配置与音频通路关系

物奇平台MIC配置与音频通路关系 是否需要申请加入数字音频系统研究开发交流答疑群(课题组)&#xff1f;可加我微信hezkz17, 本群提供音频技术答疑服务&#xff0c;群赠送语音信号处理降噪算法&#xff0c;蓝牙耳机音频&#xff0c;DSP音频项目核心开发资料, 1 255代表无效&am…

第31期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…

电子学会C/C++编程等级考试2022年12月(五级)真题解析

C/C++等级考试(1~8级)全部真题・点这里 第1题:漫漫回国路 2020年5月,国际航班机票难求。一位在美国华盛顿的中国留学生,因为一些原因必须在本周内回到北京。现在已知各个机场之间的航班情况,求问他回不回得来(不考虑转机次数和机票价格)。 时间限制:1000 内存限制:655…