1.反射(Reflection)的定义
指程序在运行期间可以获取到一个对象的全部信息。
2.java中的反射有何特别之处
反射使得Java程序在运行时可以调用反射API获取任何类的内部信息(比如成员变量,成员方法,构造器,接口,父类等),并且可以操作类的实例对象的属性以及方法。
在Java程序中,JWM加载完一个类后,在堆内存中就会产生该类的一个class对象,并且该class对象是唯一的,这个Class对象包含了该类的完整结构信息。
3.获取class类的实例
java
// 1 通过类名.class
Class<Student> studentClass1 = Student.class;
System.out.println(studentClass1.hashCode());
// 2 通过Class.forName("类的全类名") 会抛出类未找到异常
Class<?> studentClass2 = Class.forName("com.example.reflect_test.reflect.Student");
System.out.println(studentClass2.hashCode());
// 3 通过对象.getClass获得
Class<? extends Student> studentClass3 = new Student().getClass();
System.out.println(studentClass3.hashCode());
// 4 获取父类实例
Class<? super Student> superclass = studentClass1.getSuperclass();
4.获取该类的属性,方法,接口,父类等
1.获取类名
java
String name = studentClass1.getName(); //全类名
String simpleName = studentClass1.getSimpleName(); //单纯类名
2.获取属性(public)
java
studentClass1.getField("username"); //指定属性
Field[] fields = studentClass1.getFields(); // 获取所有属性
3.获取属性(public和private)
java
Field username = studentClass1.getDeclaredField("username");
Field[] declaredFields = studentClass1.getDeclaredFields();
4.获取方法(public) 包括父类的方法
java
// 无参
Method add = studentClass1.getMethod("add"); // 指定方法
Method[] methods = studentClass1.getMethods(); // 所有方法
//有参
Method declaredMethod = studentClass1.getDeclaredMethod("add",String.class,String.class);
declaredMethod.invoke(student,"111","222");
5.获取方法(public和private构造方法) 不包括父类的方法
java
Method declaredMethod = studentClass1.getDeclaredMethod("add");
Method[] declaredMethods = studentClass1.getDeclaredMethods();
6.获取类的构造器 (public构造方法)
java
Constructor<Student> constructor1 = studentClass1.getConstructor(String.class,String.class);
Constructor<?>[] constructors = studentClass1.getConstructors();
7.获取类的构造器 (public和private构造方法)
java
Constructor<Student> declaredConstructor = studentClass1.getDeclaredConstructor(String.class, String.class);
8.获取父类
java
Class<? super Student> superclass = studentClass1.getSuperclass();
9.获取接口
java
Class<?>[] interfaces = studentClass1.getInterfaces();
5.利用反射创建对象
1.使用newInstance创建(其本质上还是通过无参构造方法创建, 前提是类要有一个无参的public的构造方法)
java
Student student = studentClass1.newInstance();
2.利用类的构造器创建对象,无论构造方法是无参还是有参,私有还是公有
java
Constructor<Student> declaredConstructor = studentClass1.getDeclaredConstructor(String.class,String.class); //构造方法参数类型
// 若该构造方法是私有的,如下设置关闭检测
declaredConstructor.setAccessible(true);
Student student = declaredConstructor.newInstance("lisi","wangwu");// 构造方法参数
6.通过反射调用普通方法
- 无参
java
// 1.获取该方法实例
Method declaredMethod = studentClass1.getDeclaredMethod("add");
// 如果该方法是私有的,如下设置关闭检测,提高性能
declaredMethod.setAccessible(true);
// 2.收件利用newInstance或构造器创建对象
Student student = studentClass1.newInstance();
// 3.使用invoke执行该方法(第一个参数是实例对象,第二个是方法传入参数)
declaredMethod.invoke(student,null);
- 有参
java
// 1.获取该方法实例 (方法名+参数类型)
Method declaredMethod = studentClass1.getDeclaredMethod("add",String.class,String.class);
// 如果该方法是私有的,如下可设置可访问标志
declaredMethod.setAccessible(true);
// 2.利用newInstance或构造器创建对象
Student student = studentClass1.newInstance();
// 2.使用invoke执行该方法(第一个参数是实例对象,第二个是方法传入参数)
declaredMethod.invoke(student,"111","222");
7.通过反射操作属性
java
// 1.获取属性实例
Field username = studentClass1.getDeclaredField("username");
// 如果该属性是私有的,如下设置关闭权限检测
username.setAccessible(true);
// 2.获取对象实例
Student student = studentClass1.newInstance();
// 设置属性值
username.get(student);
// 获取属性值
username.set(student,"李四");
8.通过反射获取注解
8.1 读取类上的注解
当作用于类上时,使用类对象.getAnnotation得到注解类型,然后就可以获取变量信息了
java
// 自定义一个注解
@Target(ElementType.TYPE) // 该注解用于类上
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
String username();
int age();
}
@MyAnnotation(username = "lisi",age = 20)
class Student1 {
}
使用反射获取注解的变量
java
// 首先获取类对象
Class<Student1> student1Class = Student1.class;
// 通过 类对象.getAnnotation 获取注解类型
MyAnnotation annotation = student1Class.getAnnotation(MyAnnotation.class);
// 获取变量信息
annotation.username();
annotation.age();
8.2 读取方法上的注解
当作用于方法上时,使用方法类型实例.getAnnotation得到注解类型
java
@Target(ElementType.METHOD) // 该注解用于方法上
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
String username();
int age();
}
class Student1 {
@MyAnnotation(username = "lisi",age = 20)
public void add() {
}
}
获取注解的变量
java
Class<Student> studentClass = Student.class;
// 得到方法类型
Method add = studentClass.getDeclaredMethod("add");
// 方法类型实例.getAnnotation 获取注解
MyAnnotation annotation = add.getAnnotation(MyAnnotation.class);
// 注解里的变量
annotation.username();
annotation.age();
注解
自定义一个注解
java
@Target(ElementType.TYPE) //指定注解的生命周期(只在属性上生效)
@Retention(RetentionPolicy.RUNTIME) //指定注解可以应用的目标元素
@interface Order {
String value() default ""; //这是一个属性,并非方法,注解中比较特殊,加了括号
}
注解的生命周期分类
- ElementType.TYPE:类、接口、枚举。
- ElementType.FIELD:字段。
- ElementType.METHOD:方法。
- ElementType.PARAMETER:方法参数。
- ElementType.CONSTRUCTOR:构造函数。
- ElementType.LOCAL_VARIABLE:局部变量。
- ElementType.ANNOTATION_TYPE:注解类型。
- ElementType.PACKAGE:包。
注解可以应用的目标元素
- RetentionPolicy.SOURCE:注解仅在源代码中保留,编译时会被丢弃。
- RetentionPolicy.CLASS:注解在编译时被保留,但在运行时不可访问。
- RetentionPolicy.RUNTIME:注解在运行时保留,可以通过反射机制访问。