Java反射全面详解 目录一. 什么是反射二. 反射有什么用三. 获取 Class 字节码文件对象的三种方式重中之重面试会问3.1 Class.forName(全类名)方式获取3.2 类名.class 方式获取3.3 对象.getClass() 方式获取3.4 三种方式的通常应用场景四. 利用反射获取构造方法五. 利用反射获取属性六. 通过反射获取成员方法一. 什么是反射Java官方对反射的解释是 反射允许对封装类的字段方法和构造函数进行编程式访问。这里的字段指的就是成员变量方法指的就是成员方法构造函数就是构造方法。二. 反射有什么用我们知道在类中常用的有字段构造方法成员方法。我们的反射就是可以把一个类中所有的字段构造方法成员方法全部都获取出来。那么问题又来了获取出来有什么用呢以我们熟知的 IDEA 开发工具为例他可以在我们编写代码时自动给出提示提示我们有哪些方法可以用有哪些构造器可以使用它是怎么做到的呢不难猜出它其实就是用的反射。还有如下所示我们 new 一个对象但忘记了它可以传递哪些参数这个时候我们按键盘上的 Ctrl P 键它就会自动弹出提示我们需要传递哪些参数这个其实也使用反射做到的。刚才我们说到了 反射就是可以把一个类中所有的字段构造方法成员方法全部都获取出来。不仅如此通过反射我们可以获取的非常全面非常详细我们甚至可以获取到。当我们获取字段(变量)时不仅可以获取到该变量还能获取到该变量的访问修饰符名字类型并可以为它赋值或者获取初始值当我们获取构造方法时不仅可以获取到构造方法还能获取到修饰符名字形参还可以创建对象当我们获取成员方法时不仅可以获取到成员方法也能获取到该方法的修饰符名字形参还能获取方法的返回值抛出的异常以及方法上的注解也能获取到可以说是有什么就能获取到什么一点不剩的全都可以拿到。此外有一点要知道我们获取字段构造方法成员方法不是通过Java文件来获取的而是通过 Class 字节码文件中获取的。总的来说可以理解为一句话通过反射我们可以获取到类中的所有信息。三. 获取 Class 字节码文件对象的三种方式重中之重面试会问3.1 Class.forName(全类名)方式获取其实这种方式应该并不陌生如果有小伙伴学过JDBC的应该都大致了解过通过Class.forName(com.mysql.jdbc.Driver)来获取该类的字节码文件对象。下面 是一个JavaBean类 Account 我们通过一个例子来了解一下package cn.itcast.user.pojo; import java.io.Serializable; public class Account implements Serializable { private static final long serialVersionUID -421643127452356642L; // 账户id private Integer accountId; // 账户人名称 private String accountName; // 账户密码 private transient String accountPassword; public Account(Integer accountId, String accountName, String accountPassword) { this.accountId accountId; this.accountName accountName; this.accountPassword accountPassword; } public Account() { } Override public String toString() { return Account{ accountId accountId , accountName accountName \ , accountPassword accountPassword \ }; } public Integer getAccountId() { return accountId; } public void setAccountId(Integer accountId) { this.accountId accountId; } public String getAccountName() { return accountName; } public void setAccountName(String accountName) { this.accountName accountName; } public String getAccountPassword() { return accountPassword; } public void setAccountPassword(String accountPassword) { this.accountPassword accountPassword; } }然后我定义一个 main 方法通过 Class.forName() 的方式来获取代码如下public static void main(String[] args) { // 这里可能或出现异常由于是 main 方法中最好用 try。。。catch捕获 try { System.out.println(Class.forName(cn.itcast.user.pojo.Account));; } catch (ClassNotFoundException e) { e.printStackTrace(); } }我们直接运行此方法就可以在控制台得到 Account 类的字节码文件对象如下所示3.2 类名.class 方式获取操作方法如下代码可以看到也没有任何问题3.3 对象.getClass() 方式获取这里必须是想要反射的类的对象谁调用 getClass得到的就是谁的类对象getClass() 方法是定义在 Obeject 类中的因此所有的对象都可以使用此方法。3.4 三种方式的通常应用场景如果我想创建一个类的对象分为以下三种阶段每一个阶段都有它适当使用的场景。阶段一编写Java文件将Java文件编写成字节码文件这个阶段也被称为源代码阶段可以使用 Class.forName() 的方式来获取阶段二当我们把字节码文件加载到内存中准备运行的时候可以称为加载阶段这个阶段通常采用 类名.class 的方式获取字节码文件对象阶段三在内存中运行时我可以创建类对象这个阶段也被称为运行阶段通常采用对象.getClass()的方式获取字节码文件对象四. 利用反射获取构造方法获取类的字节码文件之后我们就可以通过字节码文件对象获取构造方法我们可以获取单个构造器可以获取所有构造器还能创建对象。如下图所示即为获取构造方法的方法我们简单测试一下如下代码实体类 Account我定义了多个构造器注释如下public class Account implements Serializable { private static final long serialVersionUID -421643127452356642L; // 账户id private Integer accountId; // 账户人名称 private String accountName; // 账户密码 private transient String accountPassword; // 全参构造器 public Account(Integer accountId, String accountName, String accountPassword) { this.accountId accountId; this.accountName accountName; this.accountPassword accountPassword; } // 一个参数的构造器 public Account(Integer accountId) { this.accountId accountId; } // 两个参数的构造器 public Account(Integer accountId, String accountName) { this.accountId accountId; this.accountName accountName; } // 无参构造器 public Account() { } }然后我们去 main 方法中测试通过反射获取构造器代码和注释如下public class Test01{ public static void main(String[] args) { // 需要先定义一个 Account 类的对象 Account account new Account(); // 根据对象获取类的字节码文件 Class clazz account.getClass(); try { // 获取参数类型为 Integer 的构造器 Constructor con clazz.getConstructor(Integer.class); // 打印输出该构造器 System.out.println(con); } catch (NoSuchMethodException e) { e.printStackTrace(); } System.out.println(----------------------------------------------); // 构造器本身也是一个对象这里我们获取多个构造器用列表进行接收 Constructor[] constructors clazz.getConstructors(); // 输出获取到的所有构造器 System.out.println(constructors); } }运行 main 方法得到如下结果在获取到类的字节码文件之后我们不仅可以向上面那样获取到构造方法还可以获取到更为详细的信息在上图中可以看到IDEA给出了大量的提示我挑几个来说一下可以干什么getParameterConunt() 获取参数个数getParameterTypes() 获取参数类型getParameter() 获取所有参数getModifiers() 获取该方法的权限修饰符如 publicprivate但返回的值是整数如果返回1则说明为public若返回2则为private。看他们的英文名字就能大概了解了我们的IDEA自动提示功能就是通过这些功能来做到的五. 利用反射获取属性利用反射我们也可以获取到类中的属性例如刚才的 Account 类我们可以获取到它的 账户id账户名称账户密码等属性相应方法如下所示我们还是需要先获取类的字节码文件再通过字节码文件的方法获取类中的属性如下所示我这里是获取所有的当然也可以获取单个的将方法的后缀 s 去掉就可调用获取单个属性的方法它也和刚才的构造方法一样可以获取属性的修饰符还可以获取到属性的变量名这里就不重复演示了。六. 通过反射获取成员方法如下图中所示的即为获取成员方法的方法我们也是要通过字节码文件对象来获取我们把刚才的 Account 类添加上 get和set方法通过字节码文件即可获取 get 和 set 方法还有几个方法我就不一一展示了也都不难。获取Class字节码文件的三种方法是面试时常常问到的一个点各位需要好好记住。