Java反射

我们先用一个思维导图来说一下关于Java反射的知识点

一 Java反射

1.1 什么是Java反射

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

那么有没有一种方法 在运行期动态的改变程序的调用行为的方法 呢?

这就是要为大家介绍的“java反射机制“。

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

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

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

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

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

总的来说,反射API用来生成类,接口或者对象的信息。

  1. Class类:反射的核心类,可以获取类的属性,方法等信息。

  1. Field类:Java.lang.reflec包中的类,表示类的成员变量,可以用来获取和设置类之中的属性值。Method类:Java.lang.reflec包中的类,表示类的方法,它可以用来获取类中的方法信息或者执行方法。

  1. Constructor类:Java.lang.reflec包中的类,表示类的构造方法。

1.2 反射使用步骤(获取Class对象、调用对象方法):

  • 获取想要操作的类的Class对象,他是反射的核心,通过Class对象我们可以任意调用类的方法。

  • 调用Class类中的方法,既就是反射的使用阶段。

  • 使用反射API来操作这些信息。

1.2 反射能做什么?

我们知道反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗!

二 类加载与反射关系

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

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

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

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

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

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

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

三 操作反射的Java类

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

java.lang.Class:代表一个类
java.lang.reflect.Constructor: 代表类的构造方法
java.lang.reflect.Method: 代表类的普通方法
java.lang.reflect.Field: 代表类的成员变量
java.lang.reflect.Modifier: 修饰符,方法的修饰符,成员变量的修饰符。
java.lang.annotation.Annotation: 在类、成员变量、构造方法、普通方法上都可以加注解

3.1 什么是Class类

对于每个类而言,JRE 都为其保留一个不变的 Class 类型的对象。一个 Class 对象包含了特定某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息。

  •  Class本身也是一个类

  •  Class 对象只能由系统建立对象

  •  一个加载的类在 JVM 中只会有一个Class实例

  •  一个Class对象对应的是一个加载到JVM中的一个.class文件

  •  每个类的实例都会记得自己是由哪个 Class 实例所生成

  •  通过Class可以完整地得到一个类中的所有被加载的结构

  •  Class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获得相应的Class对象

3.2 获取Class对象的三种方法

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

  1. 类名.class获取Class对象

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

3.2 获取Class对象的成员变量

        //通过全类名加载类的class对象
        Class cla = Class.forName("com.zy.service.impl.BookServiceImpl");
        //class对象可以认为是类的手术刀,可以解剖类里面的东西--属性,构造器,方法
        Field[] fields = cla.getFields();//只能获取public修饰的属性
        for (Field field : fields) {
            System.out.println(field);
        }
        System.out.println("------------");
        Field[] fields1 = cla.getDeclaredFields();//获取所有属性
        for (Field field : fields1) {
            System.out.println(field);
 
  • getFields(方法获取类的非私有的成员变量,数组,包含从父类继承的成员变量

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

3.3 获得Class对象的方法

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

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

  • 而来的方法

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

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

获取参数相关的属性:

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

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

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

需要注意的是:
一个类在 JVM 中只会有一个 Class 实例 ,即我们对上面获取的 c1,c2,c3进行 equals 比较,发现都是true
通过 Class 类获取成员变量、成员方法、接口、超类、构造方法等

3.4 创建类的对象(实例化对象)

 //1.通过全类名获取类的class对象
        Class cla = Class.forName(clasName);
        //2.通过Class对象获取类的无参构造器
        Constructor constructor = cla.getDeclaredConstructor();
        //3.使用构造器创建对象
        BookService bookService = (BookService) constructor.newInstance();

四 反射的优缺点

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

缺点:也正因为反射不受类的访问权限限制,其安全性低,很大部分的java安全问题都是反射导致的。相对于正常的对象的访问调用,反射因为存在类和方法的实例化过程,性能也相对较低破坏java类封装性,类的信息隐藏性和边界被破坏。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值