什么是反射?
反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
一个简单的例子
1 | public class Apple { |
输出结果为:
Apple Price:5
Apple Price:15
从这个简单的例子可以看出,一般情况下我们使用反射获取一个对象的步骤:
1 | // 获取类的 Class 对象实例 |
如果要调用某一个方法,则需要经过下面的步骤:
1 | // 获取方法的 Method 对象 |
看完这个例子之后,来看看反射常用 API 的具体解释:
常用API
获取Class对象
使用 .class 方法
这种方法适用于在编译时已经知道具体的类。
1 | Class clz = String.class; |
使用 Class.forName静态方法
适用于运行时动态获取Class对象,只需将类名作为forName方法的参数:
1 | Class clz = Class.forName("java.lang.String"); |
使用类对象的 getClass() 方法
1 | String str = new String("Hello"); |
获取类名
1 | Class<Apple> appleClass = Apple.class; |
运行结果如下:
com.kanxz.reflect.Apple
Apple
getName()方法获取的类名包含包信息。getSimpleName()方法只是获取类名,不包含包信息。
获取类修饰符
1 | System.out.println(appleClass.getModifiers()); // 1 |
类修饰符有public、private等类型,getModifiers()可以获取一个类的修饰符,但是返回的结果是int,结合Modifier提供的方法,就可以确认修饰符的类型。
1 | Modifier.isAbstract(int modifiers) |
获取包信息
1 | System.out.println(appleClass.getPackage()); // package com.kanxz.reflect |
获取构造函数
1 | /* |
一个类会有多个构造函数,getConstructors()返回的是Constructor[]数组,包含了所有声明的用public修饰的构造函数。
如果你已经知道了某个构造的参数,可以通过下面的方法获取到回应的构造函数对象:
1 | Constructor<Apple> constructor = appleClass.getConstructor(new Class[]{int.class}); |
上面获取构造函数的方式有2点需要注意:
-
只能获取到public修饰的构造函数。
-
需要捕获NoSuchMethodException异常。
初始化对象
通过反射获取到构造器之后,通过newInstance()方法就可以生成类对象。
1 | Constructor<Apple> constructor = appleClass.getConstructor(new Class[]{int.class}); |
获取Methods方法信息
下面代码是通过反射可以获取到该类的声明的成员方法信息:
1 | Method[] method = appleClass.getMethods(); |
无参的getMethods()
获取到所有public修饰的方法,返回的是Method[]数组。
无参的getDeclaredMethods()
方法到的是所有的成员方法,和修饰符无关。
对于有参的getMethods()
方法,需提供要获取的方法名以及方法名的参数。
无参的getMethods()和getDeclaredMethods()都只能获取到类声明的成员方法,不能获取到继承父类的方法。
invoke()方法
java反射提供invoke()
方法,在运行时根据业务需要调用相应的方法,这种情况在运行时非常常见,只要通过反射获取到方法名之后,就可以调用对应的方法:
1 | Constructor<Apple> constructor = appleClass.getConstructor(int.class); |
invoke方法有两个参数,第一个参数是要调用方法的对象,上面的代码中就是apple的对象,第二个参数是调用方法要传入的参数。如果有多个参数,则用数组。
如果调用的是static方法,invoke()方法第一个参数就用null代替。
获取成员变量
通过反射可以在运行时获取到类的所有成员变量,还可以给成员变量赋值和获取成员变量的值。
1 | Field[] fields1 = appleClass.getFields(); |
getFields()方法获取所有public修饰的成员变量,getField()方法需要传入变量名,并且变量必须是public修饰符修饰。
getDeclaredFields方法获取所有生命的成员变量,不管是public还是private。
成员变量赋值和取值
一旦获取到成员变量的Field引用,就可以获取通过get()方法获取变量值,通过set()方法给变量赋值:
1 | Field price = appleClass.getDeclaredField("price"); |
上面是在同一个类中测试的结果,但是在不同的类中访问其他类的私有成员变量需要加上price.setAccessible(true);
,访问私有方法也同样需要加上setAccessible(true)
。
参考: