反射概述
反射是指对于任何一个Class类,在"运行的时候"都可以直接得到这个类全部成分。
在运行时,可以直接得到这个类的构造器对象:Constructor。
在运行时,可以直接得到这个类的成员变量对象:Field。
在运行时,可以直接得到这个类的成员方法对象:Method。
这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制。
反射获取类对象
三种方式获取类对象
反射获取构造器对象并使用
Constructor<?>[] getConstructors() | 返回所有构造器对象的数组(只能拿public的) |
Constructor<?>[] getDeclaredConstructors() | 返回所有构造器对象的数组,存在就能拿到 |
Constructor<T> getConstructor(Class<?>... parameterTypes) | 返回单个构造器对象(只能拿public的) |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 返回单个构造器对象,存在就能拿到 |
Constructor类中用于创建对象的方法
T newInstance(Object... initargs) | 根据指定的构造器创建对象 |
public void setAccessible(boolean flag) | 对于非public构造器需要设置为true,表示取消访问检查,进行暴力反射 |
反射获取成员变量对象并使用
Field[] getFields() | 返回所有成员变量对象的数组(只能拿public的) |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) | 返回单个成员变量对象(只能拿public的) |
Field getDeclaredField(String name) | 返回单个成员变量对象,存在就能拿到 |
使用成员变量
void set(Object obj, Object value) | 赋值 |
Object get(Object obj) | 获取值 |
public void setAccessible(boolean flag) | 对于非public成员变量需要设置为true,表示取消访问检查,进行暴力反射 |
反射获取方法对象并使用
Method[] getMethods() | 返回所有成员方法对象的数组(只能拿public的) |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 |
Method getMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象(只能拿public的) |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象,存在就能拿到 |
使用Method对象
Object invoke(Object obj, Object... args) | 参数一:用obj对象调用该方法 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写) |
public void setAccessible(boolean flag) | 对于非public成员方法对象需要设置为true,表示取消访问检查,进行暴力反射 |
反射的作用-绕过编译阶段为集合添加数据
如下代码在编译阶段是通不过的:
ArrayList<Integer> list = new ArrayList<>();
list.add(100);
list.add(“黑马"); // 报错
list.add(99);
而泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList了,泛型相当于被擦除了。那么我们就可以用反射技术为该集合添加字符串,因为反射技术就是在运行阶段运用的。如下所示:
ArrayList<Integer> list = new ArrayList<>();
list.add(100);
//list.add("黑马"); // 报错
list.add(99);
Class<? extends ArrayList> listClass = list.getClass();
Method add = listClass.getDeclaredMethod("add", Object.class);
add.invoke(list,"heima");
System.out.println(list);
反射的作用-通用框架的底层原理
需求:给你任意一个对象,在不清楚对象字段的情况可以,可以把对象的字段名称和对应值存储到文件中去。
分析
定义一个方法,可以接收任意类的对象。
每次收到一个对象后,需要解析这个对象的全部成员变量名称。
这个对象可能是任意的,那么怎么样才可以知道这个对象的全部成员变量名称呢?
使用反射获取对象的Class类对象,然后获取全部成员变量信息。
遍历成员变量信息,然后提取本成员变量在对象中的具体值
存入成员变量名称和值到文件中去即可。
代码:
public static void save(Object obj){
try (
PrintStream ps = new PrintStream(
new FileOutputStream("E:\\data.txt",true));
){
Class<?> objClass = obj.getClass();
Field[] fields = objClass.getDeclaredFields();
ps.println("==="+objClass.getSimpleName()+"===");
for (Field field : fields) {
field.setAccessible(true);
String name = field.getName();
String value = field.get(obj)+"";
ps.println(name + "="+value);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
总结
反射的作用?
可以在运行时得到一个类的全部成分然后操作。
可以破坏封装性。(很突出)
也可以破坏泛型的约束性。(很突出)
更重要的用途是适合:做Java高级框架
基本上主流框架都会基于反射设计一些通用技术功能。