3、反射
1、英文意思
* Declared: 声明的
* 构造器: Constructors
* 属性: Fields
* 修饰符: Modifiers
* 返回类型: ReturnType
* 方法名: Name
* 参数列表: ParameterTypes
* 注解: Annotations
* 异常: ExceptionTypes
* 调用: invoke
* 接口: Interfaces
* 父类: Superclass
* 包: Package
2、概念
反射是指对于任何一个 Class 类,在 "运行的时候" 都可以直接得到这个类全部成分
- 在运行时,可以直接得到这个类的构造器对象:Constructor
- 在运行时,可以直接得到这个类的成员变量对象:Field
- 在运行时,可以直接得到这个类的成员方法对象:Method
- 这种运行时动态获取类信息以及动态调用类中成分的能力称为 Java 语言的反射机制
反射的关键:反射的第一步都是先得到编译后的 Class 类对象,然后就可以得到 Class 的全部成分
反射可以破坏封装性,私有的也可以执行了
3、类对象
// 四种方式
Class c1 = Class.forName("全类名");
Class c2 = 类名.class;
Class c3 = 类的对象.getClass();
ClassLoader classLoader = 类名.class.getClassLoader();
Class c4 = classLoader.loadClass("全类名");
Class<?> c1 = Class.forName("d12.Student");
Class<Student> c2 = Student.class;
Student student = new Student();
Class<? extends Student> c3 = student.getClass();
ClassLoader classLoader = T1.class.getClassLoader();
Class<?> c4 = classLoader.loadClass("d12.Student");
System.out.println(c1);
System.out.println(c2);
System.out.println(c3);
System.out.println(c4);
4、API
4.1、构造器对象
方法 | 说明 |
---|---|
Constructor<?>[] getConstructors() | 返回所有构造器对象的数组(只能拿 public 的) |
Constructor<?>[] getDeclaredConstructors() | 返回所有构造器对象的数组,存在就能拿到 |
Constructor<T> getConstructor(Class<?>... parameterTypes) | 返回单个构造器对象(只能拿 public 的) |
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) | 返回单个构造器对象,存在就能拿到 |
构造器对象的方法 | 说明 |
---|---|
public T newInstance(Object... initargs) | 根据指定的构造器创建对象 |
public void setAccessible(boolean flag) | 设置为 true,表示取消访问检查,进行暴力反射 |
4.2、变量对象
方法 | 说明 |
---|---|
Field[] getFields() | 返回所有成员变量对象的数组(只能拿 public 的) |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) | 返回单个成员变量对象(只能拿 public 的) |
Field getDeclaredField(String name) | 返回单个成员变量对象,存在就能拿到 |
变量对象的方法 | 说明 |
---|---|
void set(Object obj, Object value) | 赋值 obj.set(value) |
Object get(Object obj) | 获取值 obj.get() |
String getName() | 获取当前属性的名称 |
Class<?> getType() | 获取当前属性的类型 |
int getModifiers() | 获取当前属性的访问修饰符 |
public void setAccessible(boolean flag) | 设置为 true,表示取消访问检查,进行暴力反射 |
4.3、方法对象
方法 | 说明 |
---|---|
Method[] getMethods() | 返回所有成员方法对象的数组(只能拿 public 的) |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 |
Method getMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象(只能拿 public 的) |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 返回单个成员方法对象,存在就能拿到 |
方法对象的方法 | 说明 |
---|---|
Object invoke(Object obj, Object... args) | 运行方法 参数一:用 obj 对象调用该方法 参数二:调用方法的传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写) |
getModifiers() | 获取当前方法的访问修饰符 |
getReturnType() | 获取当前方法的返回类型 |
getName() | 获取当前方法的名称 |
getParameterTypes() | 获取当前方法的参数列表 |
getExceptionTypes() | 获取当前方法的异常 |
getAnnotations() | 获取当前方法的注解 |
public void setAccessible(boolean flag) | 设置为 true,表示取消访问检查,进行暴力反射 |
4.4、其他
方法 | 描述 |
---|---|
getPackage() | 获取当前类所在的包 |
getSimpleName() | 获取当前类的类名 |
getName() | 获取当前类的全路径名(包名 + 类名) |
getInterfaces() | 获取当前类实现的接口(不包括父类) |
getAnnotations() | 获取修饰当前类的注解 |
getSuperclass() | 获取当前类的父类的字节码信息 |
5、绕过编译阶段为集合添加数据
反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时是可以为集合存入其他任意类型的元素
泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成 Class 文件进入运行阶段的时候,其真实类型都是 ArrayList 了,泛型相当于被擦除了
ArrayList<String> 和 ArrayList<Integer> 的类型都是 ArrayList
ArrayList<String> list = new ArrayList<>();
list.add("你好");
// 方式一
Class<? extends ArrayList> c = list.getClass();
Method add = c.getDeclaredMethod("add", Object.class);
add.invoke(list, true);
System.out.println(list);
// 方式二
ArrayList newList = list;
newList.add(17.2);
System.out.println(list);
6、通用框架的底层原理
反射的作用
- 可以在运行时得到一个类的全部成分,然后操作
- 可以破坏封装性(很突出)
- 可以破坏泛型的约束性(很突出)
- 更重要的用途是适合:做 Java 高级框架
- 基本上主流框架都会基于反射设计一些通用技术功能
需求:给你任意一个对象,在不清楚对象字段的情况可以,可以把对象的字段名称和对应值存储到文件中去
- 定义一个方法,可以接收任意类的对象
每次收到一个对象后,需要解析这个对象的全部成员变量名称
这个对象可能是任意的,那么怎么样才可以知道这个对象的全部成员变量名称呢? - 使用反射获取对象的 Class 类对象,然后获取全部成员变量信息
遍历成员变量信息,然后提取本成员变量在对象中的具体值
存入成员变量名称和值到文件中去即可
public class Test {
public static void main(String[] args) throws Exception {
Student student = new Student(10, "张三");
System.out.println(test(student));
// 结果: Student{age:10,name:张三}
}
public static String test(Object obj) throws IllegalAccessException {
Class<?> c = obj.getClass();
Field[] fields = c.getDeclaredFields();
StringBuilder sb = new StringBuilder();
sb.append(c.getSimpleName()).append("{");
for (Field field : fields) {
field.setAccessible(true);
sb
.append(field.getName())
.append(":")
.append(field.get(obj))
.append(",");
}
sb.replace(sb.lastIndexOf(","), sb.lastIndexOf(",") + 1, "");
sb.append("}");
return sb.toString();
}
}
本文来自博客园,作者:lidongdongdong~,转载请注明原文链接:https://www.cnblogs.com/lidong422339/p/17472246.html