Java 从 0 理解反射

一. 反射是什么

1.1 概述

  • Java的反射机制:在程序的运行状态中,可以任意构造一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能成为Java语言的反射机制。反射被视为动态语言的关键。
  • 什么是动态语言:程序运行时,允许改变程序结构或者变量类型,这种语言成为动态语言。
    • java不是动态语言,它却有一个非常突出的动态相关机制:Reflection。 这个字的意思是“反射,映像,倒影”,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。
    • 换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods。
    • 这种“看透class”的能力被称为introspection(内省、内观、反省)。Reflection和introspection是常被提的两个术语。
  • 用自己的话来讲反射。就是我们平时在生成对象的时候,是通过new Class() 来创建一个对象,即我们先知道这个类是什么,地址在哪里,通过这个已经创建好了的类再来生成对象,去调用它的一个方法。即是对象先生成,我们再去调用。而反射则刚好相反。
  • 反射是一种强有力的工具,是面向抽象编程一种实现方式,它能使代码语句更加灵活,极大提高代码的运行时装配能力。

1.2 反射与new对象的区别?

  • new只能用于编译期就能确定的类型,而反射可以在运行时才确定类型并创建其对象。
  • 某些私有属性或者方法在new中不能直接调用访问,反射可以获取此类中的所有属性和方法。
  • new关键字是强类型的,效率高。反射是弱类型的效率低。
  • new关键字可以调用任何public的构造方法,而反射只能调用无参构造方法。
  • new创建对象是基于封装,有序的。而反射可以破坏封装,无视私有等修饰符。

1.3 反射提供了哪些功能?

  • 在运行时判定任意一个对象所属的类。
  • 在运行时构造任意一个类的对象。
  • 在运行时判定任意一个类所具有的成员变量和方法。
  • 在运行时调用任意一个对象的方法。
  • 生成动态代理。

1.4 使用反射能做什么

  1. 逆向代码,反编译
  2. 与自定义注解相结合,完成一些便捷功能。比如:redis自动缓存,PageQuery自动分页,CheckToken自动校验Token等各种操作(通过自定义注解,我们能拿到注解内的值,通过AOP的@Aound环绕通知功能,我们能进行切面。再通过反射调用其方法,可以进行一些预功能处理)
  3. 与业务需求相结合,能满足一些new关键词不能实现的功能,或者极大的减少开发量,提高开发效率。

1.5 反射带来的后果

  • 性能问题:
    • Java反射机制中包含了一些动态类型,所以Java虚拟机不能够对这些动态代码进行优化。因此,反射操作的效率要比正常操作效率低很多。我们应该避免在对性能要求很高的程序或经常被执行的代码中使用反射。而且如何使用反射决定了性能的高低。如果它作为程序中较少运行的部分,性能将不会成为一个问题。
  • 安全限制:
    • 使用反射通常需要程序的运行没有安全方面的限制。如果一个程序对安全性提出要求,则最好不要使用反射。
  • 程序健壮性:
    • 反射允许代码执行一些通常不被允许的操作,所以使用反射有可能会导致意想不到的后果。反射代码破坏了Java程序结构的抽象性,所以当程序运行的平台发生变化的时候,由于抽象的逻辑结构不能被识别,代码产生的效果与之前会产生差异。

二. 反射的Api

2.1 Class类

  1. 概述:
    • Java在将.class字节码文件载入时,JVM将产生一个java.lang.Class对象代表该.Class文件,从该Class对象中可以获得类的许多基本信息,这就是反射机制。
      • 反射机制所需的类主要有java.lang包中的Class类和java.lang.reflect包中的Constructor类、Field类、Method类和Parameter类。
      • Class类是一个比较特殊的类,它是反射机制的基础,Class类的对象表示正在运行的Java程序中的类或接口,也就是任何一个类被加载时,即将类的.class文件(字节码)读入内存的同时,都自动为之创建一个java.lang.Class对象。
      • Class类没有公共构造方法,其对象是JVM在加载类时通过调用类加载器中的defineClass()方法创建的,因此不能显式地创建一个Class对象。通过这个Class对象,才可以获得该对象的其他信息。
  • 获取Class对象的方式:

    • Class obj=Class.forName(String className);
      • 其中参数className表示所需类的全名;

      如果通过此类的全名找不到该类时,会跑出 ClassNotFoundException异常。

    • Class obj=类名.class;
      • 用类名调用该类的class属性来获得该类对应的Class对象。
    • obj.getClass();
      • 通过对象调用getClass()方法来获得该类对应的Class对象,即“类名.class”

    三种获取Class对象的最终结果一致,我们可以根据实际来选择合适的方法。forName适合只知道全路径类名的地方,常常用在application.yml等配置文件中定义。类名Class用在已经知道此类。对象.getClass()适合用在已经有此类的实现对象的情况下。

  1. Class反射类中包含的方法:
常用方法功能说明
public Package getPackage()返回Class对象所对应类的存放路径
public static Class<?> forName(String className)返回名称为className的类或接口的Class对象
public String getName()返回Class对象所对应类的"包.类名" 形式的全名
public Class<? super T> getSuperclass返回Class对象所对应的父类的Class对象
public Class<?>[] getInterfaces()返回Class对象所对应类所实现的所有接口
public Annotation[] getAnnotations()以数组的形式返回该程序元素上的所有注解
public Constructor getConstrutor(Class<?>…parameterTypes)返回Class对象所对应类的指定参数列表的public构造方法
public Constructor<?>[] getConstructors返回Class对象所对应类的所有public 构造方法
public Constructor getDeclaredConstructor(Class<?>…parameterTypes)返回Class对象所对应类的指定参数列表的构造方法,与访问权限无关。
public Constructor<?>[] getDeclaredConstructors()返回Class对象所对应类的所有构造方法,与访问权限无关
public Field getField(String name)返回Class对象所对应类的名为name的public成员变量
public Field[] getFields()返回Class对象所对应类的所有public成员变量
public Field[] getDeclaredFields()返回Class对象所对应类的所有成员变量,与访问权限无关
public Method getMethod(String name,Class<?>… parameterTypes)返回Class对象所对应的指定参数列表的public 方法
public Method[] getMethods()返回Class对象所对应类的所有public 成员方法
public Method[] getDeclaredMethods返回Class对象所对应类的所有成员方法,与访问权限无关
  1. 使用过程中需要注意的地方:
    1. 通过getFields()和getMethods()方法获得权限为public 成员变量和成员方法时,还包括从父类继承得到的成员变量和成员方法;而通过getDeclaredFields()和getDeclaredMethods()方法只是获得在本类中定义的所有成员变量和成员方法。
    2. 使用Declared关键字的方法,能获取到本类中的一些私有变量或者方法。
    3. 通过类.class属性获取Class对象,会使代码更安全,程序性能会更好,大部分情况下建议使用第二种方式。
    4. 获取基本类型的Class对象,可以使用对应的打包类加上 .TYPE ,例如:Integer.TYPE可以获得int的Class的对象,但要获得Integer.class的Class对象,则必须使用Integer.class。
    5. 获取到Class对象后,可以使用上方表格中的方法来操作对象。

2.2 Method类

2.3 Field类

2.4 Constructor类

三. 反射的使用

3.1 示例代码,融汇方法

3.2

四. 深入反射源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暗余

码字来之不易,您的鼓励我的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值