广告
返回顶部
首页 > 资讯 > 精选 >java反射机制及常用应用场景是什么
  • 873
分享到

java反射机制及常用应用场景是什么

2023-06-29 10:06:09 873人浏览 泡泡鱼
摘要

这篇文章主要介绍“java反射机制及常用应用场景是什么”,在日常操作中,相信很多人在java反射机制及常用应用场景是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java反射机制及常用应用场景是什么”的疑

这篇文章主要介绍“java反射机制及常用应用场景是什么”,在日常操作中,相信很多人在java反射机制及常用应用场景是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java反射机制及常用应用场景是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

    一、什么是java反射?

    在java的面向对象编程过程中,通常我们需要先知道一个Class类,然后new 类名()方式来获取该类的对象。也就是说我们需要在写代码的时候(编译期或者类加载之前)就知道我们要实例化哪一个类,运行哪一个方法,这种通常被称为静态的类加载。

    但是在有些场景下,我们事先是不知道我们的代码的具体行为的。比如,我们定义一个服务任务工作流,每一个服务任务都是对应的一个类的一个方法。

    java反射机制及常用应用场景是什么

    • 服务任务B执行哪一个类的哪一个方法,是由服务任务A的执行结果决定的

    • 服务任务C执行哪一个类的哪一个方法,是由服务任务A和B的执行结果决定的

    • 并且用户不希望服务任务的功能在代码中写死,希望通过配置的方式根据不同的条件执行不同的程序,条件本身也是变化的

    面对这个情况,我们就不能用代码new 类名()来实现了,因为你不知道用户具体要怎么做配置,这一秒他希望服务任务A执行Xxxx类的x方法,下一秒他可能希望执行Yyyy类的y方法。当然你也可以说提需求嘛,用户改一次需求,我改一次代码。这种方式也能需求,但对于用户和程序员个人而言都是痛苦,那么有没有一种方法在运行期动态的改变程序的调用行为的方法呢?这就是要为大家介绍的“java反射机制”。

    那么java的反射机制能够做那些事呢?大概是这样几种:

    • 在程序运行期动态的根据package名.类名实例化类对象

    • 在程序运行期动态获取类对象的信息,包括对象的成本变量和方法

    • 在程序运行期动态使用对象的成员变量属性

    • 在程序运行期动态调用对象的方法(私有方法也可以调用)

    二、Hello World

    先入个门,大佬可以略过这一段。我们定义一个类叫做Student

    package com.zimug.java.reflection;public class Student {    public String nickName;    private Integer age;   //这里是private    public void dinner(){        System.out.println("吃晚餐!");    }    private void sleep(int minutes){   //private修饰符        System.out.println("睡" + minutes + "分钟");    }}

    如果不用反射的方式,我相信只要学过java的朋友肯定会调用dinner方法

    Student student = new Student();student.dinner();

    如果是反射的方式我们该怎么调用呢?

    //获取Student类信息Class cls = Class.forName("com.zimug.java.reflection.Student");//对象实例化Object obj = cls.getDeclaredConstructor().newInstance();//根据方法名获取并执行方法Method dinnerMethod = cls.getDeclaredMethod("dinner");dinnerMethod.invoke(obj);  //打印:吃晚餐!

    通过上面的代码我们看到,com.zimug.java.reflection.Student类名和dinner方法名是字符串。既然是字符串我们就可以通过配置文件,或数据库、或什么其他的灵活配置方法来执行这段程序了。这就是反射最基础的使用方式。

    三、类加载与反射关系

    java的类加载机制还是挺复杂的,我们这里为了不混淆重点,只为大家介绍和“反射”有关系的一部分内容。

    java执行编译的时候将java文件编译成字节码class文件,类加载器在类加载阶段将class文件加载到内存,并实例化一个java.lang.Class的对象。比如对于Student类在加载阶段会有如下动作:

    • 在内存(方法区或叫代码区)中实例化一个Class对象,注意是Class对象不是Student对象

    • 一个Class类(字节码文件)对应一个Class对象,并且只有一个

    • 该Class对象保存了Student类的基础信息,比如这个Student类有几个字段(Filed)?有几个构造方法(Constructor)?有几个方法(Method)?有哪些注解(Annotation)?等信息

    java反射机制及常用应用场景是什么

    有了上面的关于Student类的基本信息对象(java.lang.Class对象),在运行期就可以根据这些信息来实例化Student类的对象。

    • 在运行期你可以直接new一个Student对象

    • 也可以使用反射的方法构造一个Student对象

    java反射机制及常用应用场景是什么

    但是无论你new多少个Student对象,不论你反射构建多少个Student对象,保存Student类信息的java.lang.Class对象都只有一个。下面的代码可以证明。

    Class cls = Class.forName("com.zimug.java.reflection.Student");Class cls2 = new Student().getClass();System.out.println(cls == cls2); //比较Class对象的地址,输出结果是true

    四、操作反射的java类

    了解了上面的这些基础信息,我们就可以更深入学习反射类相关的类和方法了:

    java.lang.Class: 代表一个类

    java.lang.reflect.Constructor: 代表类的构造方法

    java.lang.reflect.Method: 代表类的普通方法

    java.lang.reflect.Field: 代表类的成员变量

    Java.lang.reflect.Modifier: 修饰符,方法的修饰符,成员变量的修饰符。

    java.lang.annotation.Annotation:在类、成员变量、构造方法、普通方法上都可以加注解

    4.1.获取Class对象的三种方法

    Class.forName()方法获取Class对象

    Class cls = Class.forName("com.zimug.java.reflection.Student");

    类名.class获取Class对象

    Class clz = User.class;

    类对象.getClass()方式获取Class对象

    User user = new User();Class clazz = user.getClass();

    虽然有三种方法可以获取某个类的Class对象,但是只有第一种可以被称为“反射”。

    4.2.获取Class类对象的基本信息

    Class cls = Class.forName("com.zimug.java.reflection.Student");//获取类的包名+类名System.out.println(cls.getName());          //com.zimug.java.reflection.Student//获取类的父类Class cls = Class.forName("com.zimug.java.reflection.Student");//这个类型是不是一个注解?System.out.println(cls.isAnnotation());     //false//这个类型是不是一个枚举?System.out.println(cls.isEnum());      //false//这个类型是不是基础数据类型?System.out.println(cls.isPrimitive()); //false

    Class类对象信息中几乎包括了所有的你想知道的关于这个类型定义的信息,更多的方法就不一一列举了。还可以通过下面的方法

    获取Class类对象代表的类实现了哪些接口: getInterfaces()

    获取Class类对象代表的类使用了哪些注解: getAnnotations()

    4.3. 获得Class对象的成员变量

    结合上文中的Student类的定义理解下面的代码

    Class cls = Class.forName("com.zimug.java.reflection.Student");Field[] fields = cls.getFields();for (Field field : fields) {System.out.println(field.getName());      //nickName}fields = cls.getDeclaredFields();for (Field field : fields) {System.out.println(field.getName());      //nickName 换行  age}

    getFields()方法获取类的非私有的成员变量,数组,包含从父类继承的成员变量

    getDeclaredFields方法获取所有的成员变量,数组,但是不包含从父类继承而来的成员变量

    4.4.获取Class对象的方法

    getMethods() : 获取Class对象代表的类的所有的非私有方法,数组,包含从父类继承而来的方法

    getDeclaredMethods() : 获取Class对象代表的类定义的所有的方法,数组,但是不包含从父类继承而来的方法

    getMethod(methodName): 获取Class对象代表的类的指定方法名的非私有方法

    getDeclaredMethod(methodName): 获取Class对象代表的类的指定方法名的方法

            Class cls = Class.forName("com.zimug.java.reflection.Student");        Method[] methods = cls.getMethods();        System.out.println("Student对象的非私有方法");        for (Method m : methods) {            System.out.print(m.getName() + ",");        }        System.out.println("  end");        Method[] allMethods = cls.getDeclaredMethods();        System.out.println("Student对象的所有方法");        for (Method m : allMethods) {            System.out.print(m.getName() + ",");        }        System.out.println("  end");        Method dinnerMethod = cls.getMethod("dinner");        System.out.println("dinner方法的参数个数" + dinnerMethod.getParameterCount());        Method sleepMethod = cls.getDeclaredMethod("sleep",int.class);        System.out.println("sleep方法的参数个数" + sleepMethod.getParameterCount());        System.out.println("sleep方法的参数对象数组" + Arrays.toString(sleepMethod.getParameters()));        System.out.println("sleep方法的参数返回值类型" + sleepMethod.getReturnType());

    上面代码的执行结果如下:

    Student对象的非私有方法
    dinner,wait,wait,wait,equals,toString,hashCode,getClass,notify,notifyAll,  end
    Student对象的所有方法
    dinner,sleep,  end
    dinner方法的参数个数0
    sleep方法的参数个数1
    sleep方法的参数对象数组[int arg0]
    sleep方法的参数返回值类型void

    可以看到getMethods获取的方法中包含Object父类中定义的方法,但是不包含本类中定义的私有方法sleep。另外我们还可以获取方法的参数及返回值信息:

    获取参数相关的属性:

    • 获取方法参数个数:getParameterCount()

    • 获取方法参数数组对象:getParameters() ,返回值是java.lang.reflect.Parameter数组

    获取返回值相关的属性

    • 获取方法返回值的数据类型:getReturnType()

    4.5.方法的调用

    实际在上文中已经演示了方法的调用,如下invoke调用dinner方法

    Method dinnerMethod = cls.getDeclaredMethod("dinner");dinnerMethod.invoke(obj);  //打印:吃晚餐!

    dinner方法是无参的,那么有参数的方法怎么调用?看看invoke方法定义,第一个参数是Method对象,无论后面Object... args有多少参数就按照方法定义依次传参就可以了。

    public Object invoke(Object obj, Object... args)

    4.6.创建类的对象(实例化对象)

    //获取Student类信息Class cls = Class.forName("com.zimug.java.reflection.Student");//对象实例化Student student = (Student)cls.getDeclaredConstructor().newInstance();//下面的这种方法是已经Deprecated了,不建议使用。但是在比较旧的jdk版本中仍然是唯一的方式。//Student student = (Student)cls.newInstance();

    五、反射的常用场景

    通过配置信息调用类的方法

    结合注解实现特殊功能

    按需加载jar包或class

    5.1. 通过配置信息调用类的方法

    将上文的hello world中的代码封装一下,你知道类名className和方法名methodName是不是就可以调用方法了?至于你将className和 methodName配置到文件,还是Nacos,还是数据库,自己决定吧!

    public void invokeClaSSMethod(String className,String methodName) throws ClassNotFoundException,             NoSuchMethodException,             InvocationTargetException,             InstantiationException,             IllegalAccessException {        //获取类信息        Class cls = Class.forName(className);        //对象实例化        Object obj = cls.getDeclaredConstructor().newInstance();        //根据方法名获取并执行方法        Method dinnerMethod = cls.getDeclaredMethod(methodName);        dinnerMethod.invoke(obj);}

    5.2.结合注解实现特殊功能

    大家如果学习过mybatis plus都应该学习过这样的一个注解TableName,这个注解表示当前的实体类Student对应的数据库中的哪一张表。如下问代码所示,Student所示该类对应的是t_student这张表。

    @TableName("t_student")public class Student {    public String nickName;    private Integer age;}

    下面我们自定义TableName这个注解

    @Target(ElementType.TYPE)  //表示TableName可作用于类、接口或enum Class, 或interface@Retention(RetentionPolicy.RUNTIME) //表示运行时由JVM加载public @interface TableName {       String value() ;   //则使用@TableName注解的时候: @TableName(”t_student”);}

    有了这个注解,我们就可以扫描某个路径下的java文件,至于类注解的扫描我们就不用自己开发了,引入下面的Maven坐标就可以

    <dependency>    <groupId>org.reflections</groupId>    <artifactId>reflections</artifactId>    <version>0.9.10</version></dependency>

    看下面代码:先扫描包,从包中获取标注了TableName注解的类,再对该类打印注解value信息

    // 要扫描的包String packageName = "com.zimug.java.reflection";Reflections f = new Reflections(packageName);// 获取扫描到的标记注解的集合Set<Class<?>> set = f.getTypesAnnotatedWith(TableName.class);for (Class<?> c : set) {// 循环获取标记的注解TableName annotation = c.getAnnotation(TableName.class);// 打印注解中的内容System.out.println(c.getName() + "类,TableName注解value=" + annotation.value());

    输出结果是:

    com.zimug.java.reflection.Student类,TableName注解value=t_student

    有的朋友会问这有什么用?这有大用处了。有了类定义与数据库表的对应关系,你还能通过反射获取类的成员变量,之后你是不是就可以根据表明t_student和字段名nickName,age构建增删改查的sql了?全都构建完毕,是不是就是一个基础得Mybatis plus了?

    反射和注解结合使用,可以演化出许许多多的应用场景,特别是在框架代码实现方面。等待你去发觉啊!

    5.3.按需加载jar包或class

    在某些场景下,我们可能不希望JVM的加载器一次性的把所有classpath下的jar包装载到JVM虚拟机中,因为这样会影响项目的启动和初始化效率,并且占用较多的内存。我们希望按需加载,需要用到哪些jar,按照程序动态运行的需求取加载这些jar。

    把jar包放在classpath外面,指定加载路径,实现动态加载。

    //按路径加载jar包File file = new File("D:/com/zimug/commons-lang3.jar");URL url = file.toURI().toURL();//创建类加载器ClassLoader classLoader = new URLClassLoader(new URL[]{url});Class cls = classLoader.loadClass("org.apache.commons.lang3.StringUtils");

    同样的把.class文件放在一个路径下,我们也是可以动态加载到的

    //java的.class文件所在路径File file = new File("D:/com/zimug");URL url = file.toURI().toURL();//创建类加载器ClassLoader classLoader = new URLClassLoader(new URL[]{url});//加载指定类,package全路径Class<?> cls = classLoader.loadClass("com.zimug.java.reflection.Student");

    类的动态加载能不能让你想到些什么?是不是可以实现代码修改,不需要重新启动WEB容器?对的,就是这个原理,因为一个类的Class对象只有一个,所以不管你重新加载多少次,都是使用最后一次加载的class对象(上文讲过哦)。

    六、反射的优缺点

    优点:自由,使用灵活,不受类的访问权限限制。可以根据指定类名、方法名来实现方法调用,非常适合实现业务的灵活配置。在框架开发方面也有非常广泛的应用,特别是结合注解的使用。

    缺点:

    • 也正因为反射不受类的访问权限限制,其安全性低,很大部分的java安全问题都是反射导致的。

    • 相对于正常的对象的访问调用,反射因为存在类和方法的实例化过程,性能也相对较低

    • 破坏java类封装性,类的信息隐藏性和边界被破坏

    到此,关于“java反射机制及常用应用场景是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

    --结束END--

    本文标题: java反射机制及常用应用场景是什么

    本文链接: https://www.lsjlt.com/news/324273.html(转载时请注明来源链接)

    有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

    本篇文章演示代码以及资料文档资料下载

    下载Word文档到电脑,方便收藏和打印~

    下载Word文档
    猜你喜欢
    • java反射机制及常用应用场景是什么
      这篇文章主要介绍“java反射机制及常用应用场景是什么”,在日常操作中,相信很多人在java反射机制及常用应用场景是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”java反射机制及常用应用场景是什么”的疑...
      99+
      2023-06-29
    • 图文详解java反射机制及常用应用场景
      目录一、什么是java反射?二、Hello World三、类加载与反射关系四、操作反射的java类4.1.获取Class对象的三种方法4.2.获取Class类对象的基本信息4.3. ...
      99+
      2022-11-13
    • Java反射机制原理、Class获取方式以及应用场景详解
      目录学习背景一、Java反射机制是什么?1.1 反射原理1.2 反射例子二、Java反射机制中获取Class的三种方式及区别?2.1 Class的几种获取方式2.2 代码演示几种方式...
      99+
      2022-11-13
    • MySQL锁机制及应用场景是什么
      本文小编为大家详细介绍“MySQL锁机制及应用场景是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“MySQL锁机制及应用场景是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。锁的概述MySQL锁是操作My...
      99+
      2023-07-05
    • java中反射机制的使用场景有哪些
      这期内容当中小编将会给大家带来有关java中反射机制的使用场景有哪些,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用程序、分布式...
      99+
      2023-06-14
    • java反射机制的概念是什么及怎么用
      今天小编给大家分享一下java反射机制的概念是什么及怎么用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。一、Java反射机制...
      99+
      2023-06-30
    • Java反射机制怎么应用
      本篇内容主要讲解“Java反射机制怎么应用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java反射机制怎么应用”吧!反射基础p.s: 本文需要读者对反射机制的API有一定程度的了解,如果之前没...
      99+
      2023-06-17
    • java中反射机制的作用是什么
      本篇文章为大家展示了java中反射机制的作用是什么,内容简明扼要并且容易理解,绝对能使你眼前一亮,通过这篇文章的详细介绍希望你能有所收获。Java是什么Java是一门面向对象编程语言,可以编写桌面应用程序、Web应用程序、分布式系统和嵌入式...
      99+
      2023-06-14
    • Java中反射机制有什么用
      这篇文章主要为大家展示了“Java中反射机制有什么用”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Java中反射机制有什么用”这篇文章吧。反射:可以动态的获取指定类中的成员,以及建立类对象。好处...
      99+
      2023-06-17
    • java反射机制有什么作用
      本篇内容介绍了“java反射机制有什么作用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!本教程操作环境:windows7系统、java10版...
      99+
      2023-06-30
    • java中的反射机制怎么应用
      Java中的反射机制可以应用于以下场景: 动态加载类:可以在运行时加载指定的类,而不是在编译时就确定类的类型。 创建对象:可...
      99+
      2023-10-23
      java
    • 深入探讨Java SPI机制及其应用场景
      目录一、什么是SPI二、使用场景三、使用步骤示例四、原理解析1、SPI的核心就是ServiceLoader.load()方法2、ServiceLoader核心代码介绍一、什么是SPI...
      99+
      2023-05-17
      Java SPI机制 Java SPI接口
    • ArrayBlockQueue函数及应用场景是什么
      今天小编给大家分享一下ArrayBlockQueue函数及应用场景是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。队列在...
      99+
      2023-07-05
    • ssl原理及应用场景是什么
      SSL(Secure Sockets Layer)是一种加密协议,用于保护在互联网上传输的数据安全。它使用公钥加密来保护数据的机密性...
      99+
      2023-06-12
      ssl原理 ssl
    • java多线程应用场景是什么
      本篇内容主要讲解“java多线程应用场景是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“java多线程应用场景是什么”吧!本教程操作环境:windows7系统、java10版,DELL G3...
      99+
      2023-06-30
    • Java的引用类型及使用场景是什么
      这篇文章将为大家详细讲解有关Java的引用类型及使用场景是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。每种编程语言都有自己操作内存中元素的方式,例如在 C 和 C++ 里是通过指针,而在 Java ...
      99+
      2023-06-14
    • Redis数据类型及应用场景是什么
      小编给大家分享一下Redis数据类型及应用场景是什么,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!1. string类型1-1 ...
      99+
      2022-10-18
    • Promise.race()方法功能及应用场景是什么
      这篇文章主要介绍了Promise.race()方法功能及应用场景是什么的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇Promise.race()方法功能及应用场景是什么文章都会有所收获,下面我们一起来看看吧。当...
      99+
      2023-07-05
    • ZooKeeper核心原理及应用场景是什么
      这篇文章将为大家详细讲解有关ZooKeeper核心原理及应用场景是什么,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。为什么会有ZooKeeper 我们知道要写一个分布式应用是非常困...
      99+
      2023-06-02
    • java消息队列应用场景是什么
      这篇文章主要讲解了“java消息队列应用场景是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“java消息队列应用场景是什么”吧!一、什么是队列队列(Queue)是一种常见的数据结构,其最...
      99+
      2023-06-29
    软考高级职称资格查询
    编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
    • 官方手机版

    • 微信公众号

    • 商务合作