Java 反射机制
简介
Java反射机制是在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于人一个对象,都能够调用它的任一方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java反射机制
- 在 Java 中,只要给定类的名字,就可以通过反射机制来获得类的所有信息
反射作用
- 运行时判断任意一个对象所属的类
- 运行时构造任意一个类的对象
- 运行时判断任意一个类所具有的的成员变量和方法
- 运行时获取泛型信息
- 运行时调用任意一个对象的成员变量和方法
- 运行时处理注解
- 生成动态代理
反射组成
- java.lang.Class --- 实现反射的关键所在
- Class 类的一个实例表示 Java 的一种数据类型,包括类、接口、枚举、注解(Annotation)、数组、基本数据类型 和 void
- Class 没有公有的构造方法,Class 实例是由 JVM 在类加载时自动创建的
-
public final class Class<T> implements java.io.Serializable,GenericDeclaration,Type,AnnotatedElement { private static final int ANNOTATION= 0x00002000; private static final int ENUM = 0x00004000; private static final int SYNTHETIC = 0x00001000; private static native void registerNatives(); static { registerNatives(); } private Class(ClassLoader loader) { classLoader = loader; } }
-
- java.lang.reflect.Method --- 提供类或接口成员方法信息
- java.lang.reflect.Field --- 提供类或接口中成员变量信息
- java.lang.reflect.Constructor --- 提供类的构造方法信息
- ……
注:必须先获得Class才能获取Method、Constructor、Field
反射中类的加载过程:根据JVM工作原理,一般情况下类需要经过 加载-验证-准备-解析-初始化-使用-卸载 过程,如果需要反射的类没有在内存中,那么先经过加载这个过程并在内存中生成一个Class对象,有了这个Class对象后就可以进行反射的操作
- 一个加载的类在JVM中只会有一个Class实例
- 一个Class对象对应的是一个加载到JVM中的一个 .class 文件
- 每个类的实例都记得属于哪个Class实例生成的
- 加载到内存中的运行时类,会缓存一定的时间。在此时间之内,可通过不同的方式来获取此运行时类
获取 Class 对象的四种方式
如果想要动态获取类的所有信息,需要依靠 Class 对象。Class 类对象将一个类的方法、变量等信息告诉运行的程序
- 知道具体类的情况
-
Class<Person> clazz = Person.class;
-
- 通过对象实例获取
-
Person person = new Person(); Class<? extends Person> clazz = person.getClass();
-
- 通过 Class.forName()
-
Class<?> clazz = Class.forName("类的全路径名");
-
- 通过类加载器获取(通过类加载器获取 Class 对象不会进行初始化)
-
Class<?> clazz = ClassLoader.getSystemClassLoader().loadClass("类的全路径名");
-
反射实例
public class Person {
private String name;
public int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}
private void privateMethod(String name){
this.name = name;
System.out.println("I will change my name to "+name);
}
public void publicMethod(int age){
System.out.println("I am " + age + " years old");
}
}
反射实例使用
@Test
public void m() throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchMethodException, InvocationTargetException, NoSuchFieldException {
//获取 Person 类的 Class 对象并且创建 Person 类实例
Class<?> clazz = Class.forName("com.wen.reflection.Person");
Person person = (Person) clazz.newInstance();
System.out.println(person);
//获取 Person 类中定义的所有方法
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName());
}
//获取指定方法并调用
Method publicMethod = clazz.getDeclaredMethod("publicMethod",int.class);
publicMethod.invoke(person,23);
//获取指定成员变量并对其参数进行修改
Field name = clazz.getDeclaredField("name");
//为了对类中的参数进行修改而取消安全检查
name.setAccessible(true);
name.set(person,"cheng");
//调用 private 方法
Method privateMethod = clazz.getDeclaredMethod("privateMethod", String.class);
//为了调用private方法,而取消安全检查
privateMethod.setAccessible(true);
privateMethod.invoke(person,"wen");
}
应用场景
-
像 Spring/Spring Boot、MyBatis 等框架中都大量使用了反射机制--动态代理
- 注解 的实现也用到了反射
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· PowerShell开发游戏 · 打蜜蜂
· 在鹅厂做java开发是什么体验
· 百万级群聊的设计实践
· WPF到Web的无缝过渡:英雄联盟客户端的OpenSilver迁移实战
· 永远不要相信用户的输入:从 SQL 注入攻防看输入验证的重要性