文章目录

  • 1 什么是反射
  • 2 获取字节码文件对象的三种方式
  • 3 构造方法
  • 3.1 获取构造方法
  • 3.2 创建对象
  • 4 成员变量
  • 4.1 获取成员变量
  • 4.2 获取值、设置值
  • 5 成员方法
  • 5.1 获取成员方法
  • 5.2 运行成员方法
  • 6 案例
  • 6.1
  • 6.2


1 什么是反射

是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意属性和方法;

这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。

通俗的理解:

  • 可以无视修饰符获取类中的所有信息
    包括构造方法、属性、方法

2 获取字节码文件对象的三种方式

  1. Class.forName(“全类名”)
  2. 类名.class
  3. 对象.getClass()
//1.Class这个类里面的静态方法forName
//Class.forName("类的全类名"): 全类名 = 包名 + 类名
Class clazz1 = Class.forName("com.itheima.reflectdemo.Student");

//2.通过class属性获取
//类名.class
Class clazz2 = Student.class;

//因为class文件在硬盘中是唯一的,所以,当这个文件加载到内存之后产生的对象也是唯一的
System.out.println(clazz1 == clazz2);//true

//3.通过Student对象获取字节码文件对象
Student s = new Student();
Class clazz3 = s.getClass();

System.out.println(clazz1 == clazz2);//true
System.out.println(clazz2 == clazz3);//true

3 构造方法

3.1 获取构造方法

方法名

说明

Constructor<?>[] getConstructors()

获得所有的构造(只能public修饰)

Constructor<?>[] getDeclaredConstructors()

获得所有的构造(包含private修饰)

Constructor getConstructor(Class<?>… parameterTypes)

获取指定构造(只能public修饰)

Constructor getDeclaredConstructor(Class<?>… parameterTypes)

获取指定构造(包含private修饰)

Class<?> aClass = Class.forName("com.ldz.reflect_.Student");

// 1 获取所有public修饰的构造方法
Constructor<?>[] constructors = aClass.getConstructors();

// 2 获取全部构造方法
Constructor<?>[] constructors1 = aClass.getDeclaredConstructors();

// 3 获取public修饰的空参构造方法
Constructor<?> constructor = aClass.getConstructor();

// 4 获取只有一个参数、参数类型是String的构造方法
Constructor<?> constructor1 = aClass.getDeclaredConstructor(String.class);

// 5 获取只有一个参数、参数类型是int的构造方法
Constructor<?> constructor2 = aClass.getDeclaredConstructor(int.class);

// 6 获取构造方法修饰符
int modifiers = constructor2.getModifiers();

// 获取构造方法的参数
Parameter[] parameters = constructor3.getParameters();

3.2 创建对象

Constructor<?> constructor2 = aClass.getDeclaredConstructor(int.class);

// 暂时取消该构造方法的访问权限
constructor2.setAccessible(true);

// 创建对象
Student zs = (Student) constructor2.newInstance(20);

4 成员变量

4.1 获取成员变量

方法名

说明

Field[] getFields()

返回所有成员变量对象的数组(只能拿public的)

Field[] getDeclaredFields()

返回所有成员变量对象的数组,存在就能拿到

Field getField(String name)

返回单个成员变量对象(只能拿public的)

Field getDeclaredField(String name)

返回单个成员变量对象,存在就能拿到

Class<?> aClass = Class.forName("com.ldz.reflect_.Student2");

// 1 获取public修饰的字段
Field[] fields = aClass.getFields();

// 2 获取全部字段
Field[] declaredFields = aClass.getDeclaredFields();

// 3 获取属性为name的字段
Field name = aClass.getDeclaredField("name");

// 获取该字段的权限修饰符
int modifiers = name.getModifiers();

String name1 = name.getName();

// 获取该字段的类型
Class<?> type = name.getType();

4.2 获取值、设置值

方法

说明

void set(Object obj, Object value)

赋值

Object get(Object obj)

获取值

Student2 stu = new Student2("zhangsan", 23, "male");
Class<?> aClass = Class.forName("com.ldz.reflect_.Student2");
Field name = aClass.getDeclaredField("name");

// 获取属性名
String name1 = name.getName();

// 取消访问权限
name.setAccessible(true);

// 获取属性值
Object o = name.get(stu);

// 设置属性值
name.set(stu, "lisi");

5 成员方法

5.1 获取成员方法

方法名

说明

Method[] getMethods()

返回所有成员方法对象的数组(只能拿public的)

Method[] getDeclaredMethods()

返回所有成员方法对象的数组,存在就能拿到

Method getMethod(String name, Class<?>… parameterTypes)

返回单个成员方法对象(只能拿public的)

Method getDeclaredMethod(String name, Class<?>… parameterTypes)

返回单个成员方法对象,存在就能拿到

5.2 运行成员方法

  • Object invoke(Object obj, Object… args)

参数一:用obj对象调用该方法

参数二:调用方法的传递的参数(如果没有就不写)

返回值:方法的返回值(如果没有就不写)

//1.获取字节码文件对象
Class clazz = Class.forName("com.itheima.a02reflectdemo1.Student");

//2.获取一个对象
//需要用这个对象去调用方法
Student stu = new Student();

//3.获取一个指定的方法
//参数一:方法名
//参数二:参数列表,如果没有可以不写
Method eatMethod = clazz.getMethod("eat",String.class);

//运行
//参数一:表示方法的调用对象
//参数二:方法在运行时需要的实际参数
//注意点:如果方法有返回值,那么需要接收invoke的结果
//如果方法没有返回值,则不需要接收
String result = (String) eatMethod.invoke(stu, "重庆小面");
System.out.println(result);

6 案例

6.1

对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去

/**
 * @description 对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去
 * @author ldz
 * @date 2023/4/20 14:15
 */
public class Demo5 {

    public static void main(String[] args) throws IllegalAccessException, IOException {
        Student3 s = new Student3("小A",23,'女',167.5,"睡觉");
        Teacher t = new Teacher("播妞",10000);

        // saveObject2File(s);
        saveObject2File(t);
    }

    public static void saveObject2File(Object obj) throws IllegalAccessException, IOException {
        // 1 获取对象的字节码对象
        Class<?> aClass = obj.getClass();

        // 2 获取所有的field
        Field[] fields = aClass.getDeclaredFields();

        // 3 写
        BufferedWriter bw = new BufferedWriter(new FileWriter("src\\g.txt"));
        for (Field field: fields) {
            field.setAccessible(true);
            String name = field.getName();
            Object value = field.get(obj);

            bw.write(name + "=" + value);
            bw.newLine();
        }
        bw.close();
    }

}

6.2

利用反射根据文件中的不同类名和方法名,创建不同的对象并调用方法

// 1 加载配置文件
Properties properties = new Properties();
FileReader fr = new FileReader("src/main/resources/a.properties");
properties.load(fr);
fr.close();

// 2 根据读取的全类名创建字节码对象
String classname = (String) properties.get("classname");
Class<?> aClass = Class.forName(classname);

// 3 获取构造方法,创建对象
Constructor<?> constructor = aClass.getDeclaredConstructor();
constructor.setAccessible(true);
Object o = constructor.newInstance();

// 4 调用方法
String methodName = (String) properties.get("methodname");
Method method = aClass.getDeclaredMethod(methodName);
method.setAccessible(true);
method.invoke(o);