Java-反射

2024-01-01 10:34:36

一、什么是反射?

反射允许对封装类的成员变量,成员方法和构造方法的信息进行编程访问。

反射可以把成员变量、成员方法、构造方法挨个儿的都获取出来,并对它们进行操作。

IDEA中自动提示的功能就是用反射来做的。
在这里插入图片描述

Ctrl+p:快捷键,获取方法的形参,也是利用的反射。
在这里插入图片描述

  • 反射可以获取类中的成员变量、成员方法、构造方法。获取是从Class字节码文件中获取的。
  • 反射可以解刨成员变量、成员方法、构造方法中的信息。

添加图片注释,不超过 140 字(可选)

先获取Class对象,再从Class对象中获取成员变量、成员方法、构造方法,再去解刨获取其中的每一个具体的信息。

二、获取class对象的三种方式

  1. Class.forName(“全类名”);
  2. 类名.class;
  3. 对象.getClass();

三种方式的使用场景:
在这里插入图片描述

        //第一种方式(最常用)
        Class clazz1 = Class.forName("myreflect.Student");

        //第二种方式(一般当做参数进行传递)
        Class clazz2 = Student.class;

        //第三种方式(有这个类的对象的时候使用)
        Student s = new Student();
        Class clazz3 = s.getClass();

三、反射获取构造方法

在Java中万物皆对象

例如:Constructor类的对象就是构造方法的对象。
在这里插入图片描述
在这里插入图片描述
Student类中的内容:

package myreflect;

public class Student {
    private String name;
    private int age;

    public Student() {
    }

    public Student(String name) {
        this.name = name;
    }

    protected Student(int age) {
        this.age = age;
    }

    private 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 +
                '}';
    }
}

测试反射类中的主要内容:

        //1、获取class字节码文件对象
        Class clazz = Class.forName("myreflect.Student");

        //2、返回所有公共构造方法对象的数组
        Constructor[] cons1 = clazz.getConstructors();
        for (Constructor con : cons1) {
            System.out.println(con);
        }

        System.out.println("-------------");
        //3、返回所有构造方法的数组
        Constructor[] cons2 = clazz.getDeclaredConstructors();
        for (Constructor con : cons2) {
            System.out.println(con);
        }

        System.out.println("-------------");
        //4、返回单个公共构造方法对象
        Constructor con1 = clazz.getConstructor(String.class);
        System.out.println(con1);

        System.out.println("-------------");
        //5、获取private修饰的构造方法
        Constructor con2 = clazz.getDeclaredConstructor(String.class,int.class);
        System.out.println(con2);

        System.out.println("-------------");
        //6、获取权限修饰符,是通过整数的形式来体现的。
        int modifiers = con2.getModifiers();
        System.out.println(modifiers);

        System.out.println("-------------");
        //7、利用反射创建对象
        con2.setAccessible(true); //表示临时取消权限校验(暴力反射)
        Student stu = (Student) con2.newInstance("赵六", 28);
        System.out.println(stu);

权限修饰符所对应的数字:
在这里插入图片描述

四、反射获取成员变量

添加图片注释,不超过 140 字(可选)

Student类中的内容:

package myreflect2;

public class Student {
 private String name;
 private int age;
 public String gender;

    public Student() {
    }

    public Student(String name, int age, String gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }

    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;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", gender='" + gender + '\'' +
                '}';
    }
}

测试类中的主要内容:

package myreflect2;
import java.lang.reflect.Field;

public class Test {

    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //1、获取class字节码对象
        Class clazz = Class.forName("myreflect2.Student");

        //2.1、获取所有公共的成员变量
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        //2.2、获取所有的成员变量
        System.out.println("-------");
        Field[] fields2 = clazz.getDeclaredFields();
        for (Field field : fields2) {
            System.out.println(field);
        }

        //3.1、获取单个的成员变量(公共的)
        System.out.println("-------");
        Field gender = clazz.getField("gender");

        //3.2、获取单个的成员变量
        System.out.println("-------");
        Field name = clazz.getDeclaredField("name");

        //4、获取权限修饰符
        int modifiers = name.getModifiers();
        System.out.println(modifiers);

        //5、获取成员变量的名字
        System.out.println("-------");
        String name1 = name.getName();
        System.out.println(name1);

        //6、获取成员变量的数据类型
        System.out.println("-------");
        Class<?> type = name.getType();
        System.out.println(type);

        //7、获取成员变量记录的值
        System.out.println("-------");
        Student stu = new Student("zhansan",14,"nan");
        name.setAccessible(true); //临时取消权限校验
        Object o = name.get(stu);
        System.out.println(o);

        //8、修改对象里面记录的值
        System.out.println("-------");
        name.set(stu,"zhaoliu");
        System.out.println(stu);

    }
}

五、反射获取成员方法

添加图片注释,不超过 140 字(可选)

Student类中的内容:

package myreflect3;

import java.io.IOError;
import java.io.IOException;

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;
    }

    public void sleep(){
        System.out.println("睡觉");
    }

    private String eat(String something) throws IOException,IndexOutOfBoundsException{
        System.out.println("在吃" + something);
        return "吃饱了";
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

测试类中的内容:

package myreflect3;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;

public class Test {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1、获取class字节码文件对象
        Class clazz = Class.forName("myreflect3.Student");

        //2、获取所有公共的方法对象(包含父类中所有的公共方法)
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        //3、获取里面所有方法对象(不包含父类的 但是 可以获取本类中私有的成员方法)
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            System.out.println(declaredMethod);
        }

        //4、获取指定的单一方法
        //第一个参数:方法的名称
        //第二个参数:方法中形参的类型(具备形参的类型是考虑到方法重载的问题)
        Method eat = clazz.getDeclaredMethod("eat", String.class);

        //5、获取方法的修饰符
        int modifiers = eat.getModifiers();
        System.out.println(modifiers);

        //6、获取方法的名字
        String name = eat.getName();
        System.out.println(name);

        //7、获取方法的形参
        Parameter[] parameters = eat.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        //8、获取方法抛出的异常
        Class[] exceptionTypes = eat.getExceptionTypes();
        for (Class exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }

        //9、运行方法
        Student stu = new Student();
        eat.setAccessible(true);
        eat.invoke(stu,"米饭"); //第一个参数是对象,第二个参数是eat方法中要传递的值
        //用 stu对象 去调用 其中的 eat方法 传递的参数 是 "米饭"。

        //10、获取方法的返回值
        String result = (String) eat.invoke(stu, "小米粥");
        System.out.println(result);

    }
}

六、反射的作用

1、获取一个类里面的所有的信息,获取到之后,再执行其他的业务逻辑

2、结合配置文件,动态的创建对象并调用方法。

七、练习一

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

添加图片注释,不超过 140 字(可选)

主要代码:

package myreflect4;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;

public class Demo {
    public static void main(String[] args) throws IllegalAccessException, IOException {
        //对于任意一个对象,都可以把对象所有的字段名和值,保存到文件中去。
        Student stu = new Student("小n",23,'女',168.5f,"玩游戏");
        Teacher t = new Teacher("zhangsan",10000);
        saveObject(stu);
    }

    //把对象里面所有的成员变量名和值保存到本地文件中
    public static void saveObject(Object obj) throws IllegalAccessException, IOException {
        //获取字节码文件的对象
        Class clazz = obj.getClass();

        //创建IO流
        BufferedWriter bw = new BufferedWriter(new FileWriter("a.txt"));

        //获取所有的成员变量
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            //取消临时权限校验
            declaredField.setAccessible(true);
            //获取变量的名字
            String name = declaredField.getName();
            //获取变量中的值
            Object value = declaredField.get(obj);
            //写入文件中数据
            bw.write(name+"="+value);
            //写一行,换一行
            bw.newLine();
        }
        bw.close();
    }
}

八、练习二

反射可以和配置文件相结合,动态的创建对象,并调用方法

Student类中内容:

package myreflect5;

public class Student {
    private String name;
    private int age;

    public void study(){
        System.out.println("学生在学习!");
    }

    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 +
                '}';
    }
}

Teacher类中内容:

package myreflect5;

public class Teacher {
    private String name;
    private int salary;

    public Teacher() {
    }

    public void teach(){
        System.out.println("老师在教书!");
    }

    public Teacher(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getSalary() {
        return salary;
    }

    public void setSalary(int salary) {
        this.salary = salary;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "name='" + name + '\'' +
                ", salary=" + salary +
                '}';
    }
}

prop.properties文件中内容:

classname=myreflect5.Teacher
method=teach

测试类中内容:

package myreflect5;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

public class Demo {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1、读取配置文件中的信息
        Properties prop = new Properties();
        FileInputStream fis = new FileInputStream("prop.properties");
        prop.load(fis);
        fis.close();
        System.out.println(prop);

        //2、获取全类名和方法名
        String className = (String) prop.get("classname");
        String methodName = (String) prop.get("method");
        System.out.println(className);
        System.out.println(methodName);

        //3、利用反射创建对象并运行方法
        Class clazz = Class.forName(className);

        //4、获取构造方法
        Constructor con = clazz.getDeclaredConstructor();
        Object o = con.newInstance();
        System.out.println(o);

        //5、获取成员方法并运行
        Method method = clazz.getDeclaredMethod(methodName);
        method.setAccessible(true);
        method.invoke(o);
    }
}

九、总结

添加图片注释,不超过 140 字(可选)

power by 黑马

文章来源:https://blog.csdn.net/qq_48269763/article/details/135321200
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。