Java的反射机制
是在运行状态中, 对于任意一个类, 能够知道这个类的所有属性和方法
对于任意一个对象, 都能够调用它的任意属性和方法
这种动态获取信息以及动态调用对象方法的功能, 称为Java语言的反射机制
简单理解
利用反射可以无视修饰符, 获取类里面所有属性和方法
动态获取配置文件中的信息, 然后创建对象, 调用方法
反射初体验案例场景?
有多个类, 需要切换的创建不同类的对象, 并调用其中的方法
提供配置文件, 只需要修改配置文件, 通过反射完成需求
下面是代码演示
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
/*
提供配置文件prop.properties, 将配置文件的内容加载到Properties
*/
InputStream is = ClassLoader.getSystemClassLoader().getResourceAsStream("prop.properties");
Properties prop = new Properties();
prop.load(is);
// 释放资源
is.close();
/*
反射初体验
*/
// 通过静态方法获取Class对象
Class clazz = Class.forName(prop.getProperty("className"));
// 通过反射获取构造器
Constructor constructor = clazz.getConstructor();
// 通过构造器创建对象
Object o = constructor.newInstance();
// 通过反射获取对象方法
Method method = clazz.getMethod(prop.getProperty("methodName"));
// 运行方法
method.invoke(o);
}
}
相关文件:
Person.java
Studnet.java
Teacher.java
Worker.java
prop.properties
反射_获取Class对象
之前如果调用类中的方法?
new该类对象, 通过对象调用方法
反射调用类中的方法?
是利用Class对象来获取对象, 并调用方法的
三种方式获取Class对象(三个阶段):
1. 源代码阶段(还没有加载到内存中) -> Class类的静态方法 forName("全类名");
2. Class对象阶段(已经加载到内存) -> 类名.class
3. Runtime运行阶段(手动new对象时) -> 对象.getClass()
代码演示
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// 1.源代码阶段(还没有加载到内存中) -> Class类的静态方法 forName("全类名");
Class clazz1 = Class.forName("com.itheima05_reflect_getClass.Student");
System.out.println(clazz1); //class com.itheima05_reflect_getClass.Student
// 2.Class对象阶段(已经加载到内存) -> 类名.class
Class clazz2 = Student.class;
System.out.println(clazz2); //class com.itheima05_reflect_getClass.Student
// 3.Runtime运行阶段(手动new对象时) -> 对象.getClass()
Student stu = new Student();
Class clazz3 = stu.getClass();
System.out.println(clazz3); //class com.itheima05_reflect_getClass.Student
// 三种方式获取的Class对象是一个对象
System.out.println(clazz1 == clazz2); //true
System.out.println(clazz2 == clazz3); //true
}
}
package com.itheima05_reflect_getClass;
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public void study(){
System.out.println("study...");
}
}
在这里推荐使用第二种方式 更为简单 通过类名.class
反射获取构造方法
反射获取构造方法并利用构造方法创建对象
通过反射获取构造方法做什么?
创建对象
Constructor类中用于创建对象的方法?
T newInstance(属性1.class,属性2.class..); 根据指定的构造方法创建对象
package 反射;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/* 1.Constructor<?>[] getConstructors(); 返回所有构造方法对象的数组(仅公共的)
2.Constructor<?>[] getDeclaredConstructors(); 返回所有构造方法对象的数组(包含私有的)
3.Constructor<T> getConstructor(属性1.class,属性2.class..); 返回单个构造方法对象(仅公共的)
4.Constructor<T> getDeclaredConstructor(属性1.class,属性2.class..); 返回单个构造方法对象(包含私有的)*/
public class Test2 {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
//创建类对象
Class<Student2> clazz = Student2.class;
//获取空参构造方法对象
//因为Class类里面有newInstance方法 所以这里可以直接使用 不需要创建构造器对象
Student2 student2 = clazz.newInstance();//空参构造创建对象
System.out.println(student2);
//获取公共或者私有的构造方法对象 ()里面写的是参数.class
Constructor<Student2> declaredConstructor = clazz.getDeclaredConstructor(String.class);//返回单个构造方法对象(包含私有的)
// 如果构造方法是私有的 就临时取消检查 暴力反射
declaredConstructor.setAccessible(true);
//创建对象并赋值
Student2 stu = declaredConstructor.newInstance("白岳明");
System.out.println(stu);
}
}
这里选用了其中的两种方法 剩下两个返回数组的遍历数组进行操作就可以了 JavaBean在这里就不上传了
反射 获取Field赋值和获取值
反射对成员变量(Field对象)赋值和获取值
void set(Object o,Object value); 赋值 -> 给指定对象的成员变量赋指
Object get(Object o); 获取值 -> 获取指定对象的Field值
package 反射;
/*反射获取成员变量(Field对象)
1.Field[] getFields(); 获取所有成员变量对象数组(仅公共的)
2.Field[] getDeclaredFields(); 获取所有成员变量对象数组(包含私有的)
3.Field getField(真实存在的属性); 获取单个成员变量对象(仅公共的)
4.Field getDeclaredField(真实存在的属性); 获取单个成员变量对象(私有的)*/
import java.lang.reflect.Field;
public class Test3 {
public static void main(String[] args) throws NoSuchFieldException, InstantiationException, IllegalAccessException {
//创建类对象
Class<Student3> clazz = Student3.class;
//获取单个成员变量对象 ()里写变量的名字 不是类型
Field nameField = clazz.getField("name");
//空参构造创建对象
Student3 student1 = clazz.newInstance();
//设置成员变量的值 ()里面写给哪个对象设置 以及 设置的内容
nameField.set(student1,"baiyueming");
//打印成员变量的值
System.out.println(nameField.get(student1));
//获取单个成员变量对象 公有和私有的都可以
//获得单个成员变量对象 ()里写变量的名字 不是类型
Field moneyField = clazz.getDeclaredField("money");
//由于是私有的 所以要取消临时检查
moneyField.setAccessible(true);
//设置成员变量的值 ()里面写给哪个对象设置 以及 设置的内容
moneyField.set(student1,123);
System.out.println(moneyField.get(student1));
}
}
同理 JavaBean在这里就不写了
反射获取Method对象运行方法
package 反射;
/*反射获取成员方法(Method对象)
1.Method[] getMethods(); 返回所有公共成员方法(不包含私有,包含继承的)
2.Method[] getDeclaredMethods(); 返回所有成员方法(包含私有的,不含包继承的)
3.Method getMethod("方法名",属性.class..); 返回指定公共成员方法
4.Method getDeclaredMethod("方法名",属性.class..); 返回指定私有成员方法*/
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test4 {
public static void main(String[] args) throws NoSuchMethodException, InstantiationException, IllegalAccessException, InvocationTargetException {
//创建类对象
Class<Student4> clazz = Student4.class;
//获取指定所有成员方法对象 ()里面写方法名 以及方法需要的参数类型
Method method = clazz.getDeclaredMethod("function4",String.class);
//由于是私有的 所以要取消临时检验
method.setAccessible(true);
//通过空参构造创建对象
Student4 student4 = clazz.newInstance();
//由于有返回值所以需要接受一下
Object name = method.invoke(student4, "白岳明");
//打印结果
System.out.println(name);
}
}