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)); |
| |
| } |
| |
| 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(); |
| } |
| } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步