一、什么是反射
反射允许对封装类的字段,方法和构造函数的信息进行编程访问
idea中自动提示的功能就是反射实现的
说白了就是能从类中拿东西
这里类中数据的获取是从class文件得到的,而不是java文件,所以在获取之前我们需要先获取class文件的对象。
二、如何获取class对象
①Class.forName("全类名");②类名.class
③对象.getClass();
这里的三个方法正好对应三个阶段
①源代码阶段
②加载阶段
③运行阶段
public class ReflectionDemo {
public static void main(String[] args) throws ClassNotFoundException {
//1.第一种获取class对象的方法
// 全类名:报名+类名
Class clazz = Class.forName("com.qcqc.javaStudy.Student");
//2.第二种方式获取class对象
Class clazz2 = Student.class;
//3.第三种方式获取class对象
Student s = new Student();
Class clazz3 = s.getClass();
// 注意点:
//这三种方式创建的class对象为同一个对象
//第一种方式最为常用
//第二种方式常作为参数传递
//第三种方式有一定局限性,仅当已经存在对象时才能使用
}
}
注意点:
这三种方式创建的class对象为同一个对象
第一种方式最为常用
第二种方式常作为参数传递
第三种方式有一定局限性,仅当已经存在对象时才能使用
三、获取构造方法,成员变量和方法
在java中万物皆对象,所以获取到的都是对象
构造方法:Constructor类
字段:Field类
成员方法:Method类
一、利用反射获取构造方法
public class ReflectionDemo2 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
Class clazz = Class.forName("com.qcqc.javaStudy.Student");
System.out.println("--------getConstructors--------");
Constructor[] cons = clazz.getConstructors();
for (Constructor con : cons) {
System.out.println(con);
}
System.out.println("--------getDeclaredConstructors--------");
Constructor[] dcons = clazz.getDeclaredConstructors();
for (Constructor dcon : dcons) {
System.out.println(dcon);
}
System.out.println("--------getConstructor--------");
Constructor con = clazz.getConstructor();
System.out.println(con);
System.out.println("--------getDeclaredConstructor--------");
Constructor dcon = clazz.getDeclaredConstructor(String.class,int.class);
System.out.println(dcon);
}
}
获取单个构造函数时,需要传入与构造函数相同的参数!
构造器的方法:
变量和类型 | 方法 | 描述 |
---|---|---|
boolean | equals(Object obj) | 将此 构造器 与指定的对象进行比较。 |
AnnotatedType | getAnnotatedReceiverType() | 返回一个 AnnotatedType 对象,该对象表示使用类型来指定此 Executable 对象所表示的方法/构造函数的接收器类型。 |
AnnotatedType | getAnnotatedReturnType() | 返回一个 AnnotatedType 对象,该对象表示使用类型来指定此可执行文件所表示的方法/构造函数的返回类型。 |
<T extends Annotation>T | getAnnotation(类<T> annotationClass) | 返回该元素的,如果这样的注释 *,*否则返回null指定类型的注释。 |
Annotation[] | getDeclaredAnnotations() | 返回 直接出现在此元素上的注释。 |
类<T> | getDeclaringClass() | 返回表示声明此对象表示的构造方法的类的 类 对象。 |
Type[] | getGenericExceptionTypes() | 返回 Type 对象的数组, Type 对象表示声明由此可执行对象引发的异常。 |
Type[] | getGenericParameterTypes() | 返回 Type 对象的数组, Type 对象表示此对象表示的可执行文件的声明顺序的形式参数类型。 |
String | getName() | 以字符串形式返回此构造函数的名称。 |
Annotation[][] | getParameterAnnotations() | 返回 Annotation 的数组数组,这些数组表示由此对象表示的 Executable 声明顺序的形式参数的注释。 |
int | getParameterCount() | 返回此对象表示的可执行文件的形式参数(无论是显式声明还是隐式声明,或两者都不)。 |
TypeVariable<构造器<T>>[] | getTypeParameters() | 返回的数组 TypeVariable 对象表示通过此表示的一般声明声明的类型变量 GenericDeclaration 目的,在声明的顺序。 |
int | hashCode() | 返回此 构造器 的哈希 构造器 。 |
boolean | isSynthetic() | 如果此可执行文件是合成构造,则返回true ; 否则返回false 。 |
boolean | isVarArgs() | 如果声明此可执行文件采用可变数量的参数,则返回true ; 否则返回false 。 |
T | newInstance(Object... initargs) | 使用此 构造器 对象表示的构造方法,使用指定的初始化参数创建和初始化构造函数声明类的新实例。 |
void | setAccessible(boolean flag) | 将此反射对象的 accessible 标志设置为指示的布尔值。 |
String | toGenericString() | 返回描述此 构造器 的字符串,包括类型参数。 |
String | toString() | 返回描述此 构造器 的字符串。 |
也可以使用该构造器创建对象
Student stu = (Student) dcon.newInstance("张三", 18);
System.out.println(stu);
二、利用反射获取成员变量
System.out.println("--------getDeclaredFields--------");
Field[] fields = clazz.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("--------getDeclaredFields--------");
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
System.out.println(field);
}
System.out.println("--------获取指定成员变量--------");
Field gender = clazz.getField("gender");
System.out.println(gender.getModifiers());
System.out.println(gender.getName());
成员变量的方法:
变量和类型 | 方法 | 描述 |
---|---|---|
boolean | equals(Object obj) | 将此 字段 与指定的对象进行比较。 |
Object | get(Object obj) | 返回指定对象上此 字段 表示的字段的值。 |
AnnotatedType | getAnnotatedType() | 返回AnnotatedType对象,该对象表示使用类型来指定此Field表示的字段的声明类型。 |
<T extends Annotation>T | getAnnotation(类<T> annotationClass) | 返回该元素的,如果这样的注释 *,*否则返回null指定类型的注释。 |
<T extends Annotation>T[] | getAnnotationsByType(类<T> annotationClass) | 返回与此元素 关联的注释。 |
boolean | getBoolean(Object obj) | 获取静态或实例 boolean 字段的值。 |
byte | getByte(Object obj) | 获取静态或实例 byte 字段的值。 |
char | getChar(Object obj) | 获取类型为 char 的静态或实例字段的值,或通过扩展转换获得可转换为类型 char 的另一种基本类型的值。 |
类<?> | getDeclaringClass() | 返回 类 表示声明此表示的字段的类或接口对象 字段 对象。 |
double | getDouble(Object obj) | 获取类型为 double 的静态或实例字段的值,或通过扩展转换获得可转换为类型 double 的其他基本类型的值。 |
float | getFloat(Object obj) | 获取类型为 float 的静态或实例字段的值,或通过扩展转换获得可转换为类型 float 的另一种基本类型的值。 |
Type | getGenericType() | 返回 Type 对象,该对象表示此 字段 对象表示的字段的声明类型。 |
int | getInt(Object obj) | 获取类型为 int 的静态或实例字段的值,或通过扩展转换获得可转换为类型 int 的另一种基本类型的值。 |
long | getLong(Object obj) | 获取类型为 long 的静态或实例字段的值,或通过扩展转换获得可转换为类型 long 的另一种基本类型的值。 |
int | getModifiers() | 以整数形式返回此 字段 对象表示的字段的Java语言修饰符。 |
String | getName() | 返回此 字段 对象表示的字段的名称。 |
short | getShort(Object obj) | 获取类型为 short 的静态或实例字段的值,或通过扩展转换获得可转换为类型 short 的另一种基本类型的值。 |
类<?> | getType() | 返回 类 对象,该对象标识此 字段 对象表示的字段的声明类型。 |
int | hashCode() | 返回此 字段 的哈希 字段 。 |
boolean | isEnumConstant() | 如果此字段表示枚举类型的元素,则返回true ; 否则返回false 。 |
boolean | isSynthetic() | 如果此字段是合成字段,则返回true ; 否则返回false 。 |
void | set(Object obj, Object value) | 将指定对象参数上此 字段 对象表示的字段设置为指定的新值。 |
void | setAccessible(boolean flag) | 将此反射对象的 accessible 标志设置为指示的布尔值。 |
void | setBoolean(Object obj, boolean z) | 将字段的值设置为指定对象上的 boolean 。 |
void | setByte(Object obj, byte b) | 将字段的值设置为指定对象上的 byte 。 |
void | setChar(Object obj, char c) | 将字段的值设置为指定对象上的 char 。 |
void | setDouble(Object obj, double d) | 将字段的值设置为指定对象上的 double 。 |
void | setFloat(Object obj, float f) | 将字段的值设置为指定对象上的 float 。 |
void | setInt(Object obj, int i) | 将字段的值设置为指定对象上的 int 。 |
void | setLong(Object obj, long l) | 将字段的值设置为指定对象上的 long 。 |
void | setShort(Object obj, short s) | 将字段的值设置为指定对象上的 short 。 |
String | toGenericString() | 返回描述此 字段 的字符串,包括其泛型类型。 |
String | toString() | 返回描述此 字段 的字符串。 |
三、利用反射获取成员方法
System.out.println("--------getMethods--------");
Method[] methods = clazz.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("--------getDeclaredMethods--------");
Method[] declaredMethods = clazz.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
System.out.println("--------getMethod--------");
Method setAge = clazz.getMethod("setAge",int.class);
System.out.println(setAge.getModifiers());
Method eat = clazz.getMethod("eat", String.class);
Object invoke = eat.invoke(stu,"答辩");
System.out.println(invoke.toString());
在获取方法的时候需要提供方法的形参,这是为了方法的重载
成员方法的方法:
变量和类型 | 方法 | 描述 |
---|---|---|
boolean | equals(Object obj) | 将此 方法 与指定的对象进行比较。 |
AnnotatedType | getAnnotatedReturnType() | 返回一个 AnnotatedType 对象,该对象表示使用类型来指定此可执行文件表示的方法/构造函数的返回类型。 |
<T extends Annotation>T | getAnnotation(类<T> annotationClass) | 返回该元素的,如果这样的注释 *,*否则返回null指定类型的注释。 |
Annotation[] | getDeclaredAnnotations() | 返回 直接出现在此元素上的注释。 |
类<?> | getDeclaringClass() | 返回表示声明此对象表示的方法的类或接口的 类 对象。 |
Object | getDefaultValue() | 返回此 方法 实例表示的注释成员的默认值。 |
Type[] | getGenericExceptionTypes() | 返回 Type 对象的数组, Type 对象表示声明由此可执行对象引发的异常。 |
Type[] | getGenericParameterTypes() | 返回一个 Type 对象的数组, Type 对象表示此对象表示的可执行文件的声明顺序的形式参数类型。 |
Type | getGenericReturnType() | 返回一个 Type 对象,该对象表示此 方法 对象表示的方法的正式返回类型。 |
String | getName() | 返回此 方法 对象表示的方法的名称,如 String 。 |
Annotation[][] | getParameterAnnotations() | 返回 Annotation 的数组数组,这些数组表示由此对象表示的 Executable 声明顺序的形式参数的注释。 |
int | getParameterCount() | 返回此对象表示的可执行文件的形式参数(无论是显式声明还是隐式声明,或两者都不)。 |
类<?> | getReturnType() | 返回一个 类 对象,该对象表示此 方法 对象表示的方法的正式返回类型。 |
TypeVariable<方法>[] | getTypeParameters() | 返回的数组 TypeVariable 对象表示通过此表示的一般声明声明的类型变量 GenericDeclaration 目的,在声明的顺序。 |
int | hashCode() | 返回此 方法 的哈希 方法 。 |
Object | invoke(Object obj, Object... args) | 在具有指定参数的指定对象上调用此 方法 对象表示的基础方法。 |
boolean | isBridge() | 如果此方法是桥接方法,则返回true ; 否则返回false 。 |
boolean | isDefault() | 如果此方法是默认方法,则返回true ; 否则返回false 。 |
boolean | isSynthetic() | 如果此可执行文件是合成构造,则返回true ; 否则返回false 。 |
boolean | isVarArgs() | 如果声明此可执行文件采用可变数量的参数,则返回true ; 否则返回false 。 |
void | setAccessible(boolean flag) | 将此反射对象的 accessible 标志设置为指示的布尔值。 |
String | toGenericString() | 返回描述此 方法 的字符串,包括类型参数。 |
String | toString() | 返回描述此 方法 的字符串。 |
可以使用invoke方法执行该成员方法
三、反射的作用
①获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
②结合配置文件,动态的创建对象并调用方法
四、练习
一、保存信息
public class ReflectionDemo {
public static void main(String[] args) throws IOException, IllegalAccessException {
Student s = new Student("小A",23,"女",167.5,"睡觉");
Teacher t = new Teacher("波妞",10000);
saveObject(s);
saveObject(t);
}
private static void saveObject(Object obj) throws IllegalAccessException, IOException {
//利用反射获取类的所有信息
Class clazz = obj.getClass();
//创建io流
BufferedWriter bw = new BufferedWriter(new FileWriter("obj.txt",true));
//获取成员变量
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
//获取成员变量的名字
String fieldName = field.getName();
//获取成员变量的值
Object o = field.get(obj);
//写出数据
bw.write(fieldName + " = " + o);
bw.newLine();
}
//关闭io流
bw.close();
}
}
Student.java
public class Student {
private String name;
private int age;
private String gender;
private double height;
private String hobby;
public Student() {
}
public Student(String name, int age, String gender, double height, String hobby) {
this.name = name;
this.age = age;
this.gender = gender;
this.height = height;
this.hobby = hobby;
}
/**
* 获取 * @return name
*/ public String getName() {
return name;
}
/**
* 设置 * @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取 * @return age
*/ public int getAge() {
return age;
}
/**
* 设置 * @param age
*/
public void setAge(int age) {
this.age = age;
}
/**
* 获取 * @return gender
*/ public String getGender() {
return gender;
}
/**
* 设置 * @param gender
*/
public void setGender(String gender) {
this.gender = gender;
}
/**
* 获取 * @return height
*/ public double getHeight() {
return height;
}
/**
* 设置 * @param height
*/
public void setHeight(double height) {
this.height = height;
}
/**
* 获取 * @return hobby
*/ public String getHobby() {
return hobby;
}
/**
* 设置 * @param hobby
*/
public void setHobby(String hobby) {
this.hobby = hobby;
}
public String toString() {
return "Student{name = " + name + ", age = " + age + ", gender = " + gender + ", height = " + height + ", hobby = " + hobby + "}";
}
}
Teacher.java
public class Teacher {
private String name;
private int salary;
public Teacher() {
}
public Teacher(String name, int salary) {
this.name = name;
this.salary = salary;
}
/**
* 获取 * @return name
*/ public String getName() {
return name;
}
/**
* 设置 * @param name
*/
public void setName(String name) {
this.name = name;
}
/**
* 获取 * @return salary
*/ public int getSalary() {
return salary;
}
/**
* 设置 * @param salary
*/
public void setSalary(int salary) {
this.salary = salary;
}
public String toString() {
return "Teacher{name = " + name + ", salary = " + salary + "}";
}
}
二、读取配置信息
public class ReflectionDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
// ./Day38/src/com/qcqc/javaStudy/Case2/prop.properties
//1.读取配置文件中的信息 Properties prop = new Properties();
prop.load(new FileInputStream("./Day38/src/com/qcqc/javaStudy/Case2/prop.properties"));
String className = (String) prop.get("class");
String methodName = (String) prop.get("method");
//获取class对象
Class clazz = Class.forName(className);
//创建对象
Object o = clazz.getConstructor().newInstance();
//调用方法
clazz.getMethod(methodName)
.invoke(o);
}
}
配置文件
class=com.qcqc.javaStudy.Case2.Student
method=study