Java基础——反射(Reflection)基础

1. 反射概述

1.1 反射是什么?

Java语言的反射机制: 在Java中,运行状态时,只要给定类的名字,就能知道这个类的所有信息,可以构造出指定对象,可以调用它的任意一个属性和方法。这种动态获取信息以及动态调用对象的方法的功能是Java语言的反射机制。

一般,我们使用某个类时一定知道这个类是什么类,有什么作用,对这个类进行实例化,使用这个类对象进行操作。

反射则是在一开始并不知道我们要初始化的类对象是什么,自然无法new出对象,这时候需要进行反射调用。

反射允许对封装类的字段、方法和构造函数的信息进行编程访问。

1.2 反射提供的功能

Java反射机制主要提供以下功能:

  1. 在运行时判断任意一个对象所属的类。

  2. 在运行时构造任意一个类的对象。

  3. 在运行时判断任意一个类所具有的成员变量和方法。

  4. 在运行时调用任意一个对象的方法。

1.3 反射的作用

反射的作用:

  • 动态的加载类,动态获取类的信息(属性、方法、构造器)

  • 动态的构造对象

  • 动态调用类和对象的任意方法、构造器

  • 获取泛型信息

  • 处理注解

  • 动态代理

  • ...

2. 获取类的信息

2.1 获取反射中的Class对象

反射始于Class,Class是一个类,是一个用来描述类的类,封装了当前对象所对应类的信息。对于每个类,JRE都为其保留一个不变的Class类型的对象。一个类在JVM中只会有一个Class实例。

获取Class类对象三种方法:

  1. Class.forNam(全类名) 静态方法。源代码阶段(.java -> .class)
  2. 类名.class() 方法(基本类型只可该方法获得Class对象)。加载阶段(.class加载到内存中)
  3. 对象.getClass() 方法。运行阶段(内存中运行 A a = new A();)

三种方法实现代码如下:

java 复制代码
//第一种,使用 Class.forName 静态方法。
Class clazz1 = Class.forName("reflect.Person");
//第二种,使用 .class 方法。
Class clazz2 = Person.class;
//第三种,使用类对象的 getClass() 方法。
Person person =  new Person("浅浅",18);
Class clazz3 = person.getClass();

判断是否为某个类的实例

一般,使用instanceof关键字来判断是否为某个类的实例:

java 复制代码
public native boolean isInstance(Object obj);

也可以使用反射中Class对象的isInstance()方法来判断是否为某个类的实例:

java 复制代码
public boolean isAssignableFrom(Class<?> cls)

2.2 通过反射创建类对象

主要两种方式:

1.通过 Class对象的newInstance() 方法(只能使用默认的无参数构造方法)。

2.通过 Constructor对象的newInstance() 方法(可以选择特定构造方法)。

其实, class.newInstance() 内部实现也是通过 Constructor。而且现在已经标记为 @Deprecated(since="9"),建议使用 Constructor 。

java 复制代码
//获取class对象
Class clazz = Class.forName("reflect.Person");

//如果有默认构造方法,就使用这个,先通过Class对象获取指定的Constructor对象
Person p1 = (Person) clazz.getConstructor().newInstance();
//指定构造方法
Person p2 = (Person) clazz.getDeclaredConstructor(String.class, int.class).newInstance("dr", 1);

2.3 通过反射获取类的成员变量

获取成员变量的两个方法:

  1. Field getField(String name): 获得命名的公共字段,只能获取 public 修饰的变量,如果是私有变量,会报错NoSuchField。
  2. Field[] getFields(): 获得类的所有公共字段。
  3. Field getDeclaredField(String name): 获得类声明的字段,在不知道变量的权限修饰符的时候,建议使用, 比较保险。
  4. Field[] getDeclaredFields(): 获得类声明的所有字段。

修改变量的值的两类方法:

  1. 引用类型 :只有一个方法 set(Object obj, Object value)
  2. 基本类型 :为每个基本类型,都提供了一个方法,例如 setInt(Object obj, int i)setLong(Object obj, long l) 大家使用时,根据不同的类型,选择不同的方法。

注:若修改的属性为私有属性,则需要先设置field.setAccessible(true),设置之后才可以修改值。

java 复制代码
//获取class对象
Class clazz = Class.forName("reflect.Person");
//构造对象
Person p = (Person) clazz.getDeclaredConstructor(String.class, int.class).newInstance("dr", 18);
//获取指定变量 name
Field nameField = clazz.getField("name");
//修改变量的值
nameField.set(p,"张三");
//获取指定变量 age 
Field ageField = clazz.getDeclaredField("age");
//age 是private变量,需要先设置可用
ageField.setAccessible(true);
//修改变量的值
ageField.setInt(p,17);

2.4 通过反射获取类的方法

获取类方法的两个方法:

  1. Method getMethod(String name, Class[] params): 使用特定的参数类型,获得命名的公共方法。
  2. Method[] getMethods(): 获得类的所有公共方法。
  3. Method getDeclaredMethod(String name, Class[] params): 使用特写的参数类型,获得类声明的命名的方法。
  4. Method[] getDeclaredMethods(): 获得类声明的所有方法。
java 复制代码
//获取class对象
Class clazz = Class.forName("reflect.Person");
//构造对象
Person p = (Person) clazz.getDeclaredConstructor(String.class, int.class).newInstance("dr", 18);
//获取指定方法 "addFavorite"
Method method = clazz.getMethod("addFavorite", String.class);
//调用对象方法
method.invoke(p, "篮球");
//获取指定方法 "changeAge"
Method privateMethod = clazz.getDeclaredMethod("changeAge", int.class);
//changeAge 是private方法,需要先设置可用
privateMethod.setAccessible(true);
privateMethod.invoke(p, 17);

注:当我们从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法。

java 复制代码
public Object invoke(Object obj, Object... args)

3. 反射进阶

本文介绍了反射的基本使用方法,深入进阶使用请看后续文章...

相关推荐
皮皮林55110 小时前
IDEA 源码阅读利器,你居然还不会?
java·intellij idea
卡尔特斯14 小时前
Android Kotlin 项目代理配置【详细步骤(可选)】
android·java·kotlin
白鲸开源14 小时前
Ubuntu 22 下 DolphinScheduler 3.x 伪集群部署实录
java·ubuntu·开源
ytadpole14 小时前
Java 25 新特性 更简洁、更高效、更现代
java·后端
纪莫14 小时前
A公司一面:类加载的过程是怎么样的? 双亲委派的优点和缺点? 产生fullGC的情况有哪些? spring的动态代理有哪些?区别是什么? 如何排查CPU使用率过高?
java·java面试⑧股
JavaGuide15 小时前
JDK 25(长期支持版) 发布,新特性解读!
java·后端
用户37215742613515 小时前
Java 轻松批量替换 Word 文档文字内容
java
白鲸开源15 小时前
教你数分钟内创建并运行一个 DolphinScheduler Workflow!
java
Java中文社群16 小时前
有点意思!Java8后最有用新特性排行榜!
java·后端·面试
代码匠心16 小时前
从零开始学Flink:数据源
java·大数据·后端·flink