Bootstrap

自制笔记 | Java基础——反射(持续更新...)

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

反射

获取class对象的三种方式:

Class.forName("全类名")
类名.class
对象.getClass()

使用这三种方式的时机:

获取Class对象方式

源代码阶段,字节码文件还在硬盘中,未加载到内存,使用第一种方式;在加载阶段,使用第二种方;在运行阶段,使用第三种方式

public class Test1 {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.第一种方式
        //全类名:包名 + 类名
        //最为常用的
        Class clazz1 = Class.forName("test1.Student");

        //2.第二种方式
        //一般更多的是当做参数进行传递
        Class clazz2 = Student.class;

        //3.第三种方式
        //当我们已经有了这个类的对象时,才可以使用
        Student s = new Student();
        Class clazz3 = s.getClass();
    }
}

利用反射获取构造方法:

Class类中用于获取构造方法的方法:

Constructor<?>[] getConstructors():返回所有公共构造方法对象的数组
Constructor<?>[] getDeclaredConstructors():返回所有构造方法对象的数组
Constructor<T> getConstructor(Class<?>... parameterTypes):返回单个公共构造方法对象
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回单个构造方法对象

Constructor类中用于创建对象的方法:

T newInstance(Object... initargs):根据指定的构造方法创建对象
setAccessible(boolean flag):设置为true,表示取消访问检查,可越过private权限来构造对象

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

    public Student() {
    }

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

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

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

    /**
     * 获取
     * @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;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}
public class Test2 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.获取class字节码文件对象
        Class clazz = Class.forName("test2.Student");

        //2.获取构造方法
        Constructor[] cons1 = clazz.getConstructors();
        for (Constructor con : cons1) {
            System.out.println(con);
        }

        Constructor[] cons2 = clazz.getDeclaredConstructors();
        for (Constructor con : cons2) {
            System.out.println(con);
        }

        Constructor con1 = clazz.getConstructor();
        System.out.println(con1);

        Constructor con2 = clazz.getDeclaredConstructor(int.class);
        System.out.println(con2);

        Constructor con3 = clazz.getDeclaredConstructor(String.class, int.class);
        System.out.println(con3);

        int modifiers = con3.getModifiers(); //不同权限修饰符以不同的整数表示
        System.out.println(modifiers);

        Parameter[] parameters = con3.getParameters(); //获取所有参数
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }

        //暴力反射:表示临时取消权限检验,使得即使是private的构造方法,也可以用来构造对象
        con3.setAccessible(true);
        Student stu = (Student) con3.newInstance("张三", 23);
        System.out.println(stu);
    }
}

反射获取成员变量:

Class类中用于获取成员变量的方法:

Field[] getFields():返回所有公共成员变量对象的数组
Field[] getDeclaredFields():返回所有成员变量对象的数组
Field getField(String name):返回单个公共成员变量对象
Field getDeclaredField(String name):返回单个成员变量对象

Field类中用于创建对象的方法:

void set(Object obj, Object value):赋值
Object get(Object obj):获取值

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

    /**
     * 获取
     * @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;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + ", gender = " + gender + "}";
    }
}
public class Test3 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        //1.获取class字节码文件的对象
        Class<?> clazz = Class.forName("test3.Student");

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

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

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

        //获取成员变量的名字
        String n = name.getName();
        System.out.println(n);

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

        //获取成员变量记录的值
        Student s = new Student("zhangsan", 23, "男");
        name.setAccessible(true); //这里需要临时取消权限检验,因为name是private的
        String value = (String) name.get(s);
        System.out.println(value);

        //修改对象里面记录的值
        name.set(s, "zhanghaisen");
        System.out.println(s);
    }
}

利用反射获取成员方法:

Class类中用于获取成员方法的方法:

Method[] getMethods():返回所有公共成员方法对象的数组,包括继承的
Method[] getDeclaredMethods():返回所有成员方法对象的数组,不包括继承的
Method getMethod(String name, Class<?>... parameterTypes):返回单个公共成员方法对象
Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回单个成员方法对象

Method类中用于创建对象的方法:

Object invoke(Object obj, Object... args):运行方法
参数一:用obj对象调用该方法
参数二:调用方法的传递的参数(如果没有就不写)
返回值:方法的返回值(如果没有就不写)

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

    public Student() {
    }

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

    /**
     * 获取
     * @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;
    }

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

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

    private String eat(String sth) throws IOException, NullPointerException {
        System.out.println("在吃" + sth);
        return "好吃";
    }

    private void eat(String sth, int a) {
        System.out.println("在吃" + sth);
    }
}
public class Test4 {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1.获取class字节码文件对象
        Class clazz = Class.forName("test4.Student");

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

        //获取里面所有的方法(不能获取父类的,但是可以获取本类中私有的方法)
        /*Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }*/

        //获取指定的单一方法
        Method m = clazz.getDeclaredMethod("eat", String.class);
        System.out.println(m);

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

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

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

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

        //方法运行
        Student s = new Student();
        m.setAccessible(true);
        String res = (String) m.invoke(s, "汉堡包");
        System.out.println(res);

    }
}

反射的作用:

① 获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
② 结合配置文件,动态地创建对象并调用方法

练习:

反射练习1

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

    public Student() {
    }

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

    /**
     * 获取
     * @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;
    }

    public String toString() {
        return "Student{name = " + name + ", age = " + age + "}";
    }
}
public class Teacher {
    private String name;
    private int age;
    private double height;
    private String gender;

    public Teacher() {
    }

    public Teacher(String name, int age, double height, String gender) {
        this.name = name;
        this.age = age;
        this.height = height;
        this.gender = gender;
    }

    /**
     * 获取
     * @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 height
     */
    public double getHeight() {
        return height;
    }

    /**
     * 设置
     * @param height
     */
    public void setHeight(double height) {
        this.height = height;
    }

    /**
     * 获取
     * @return gender
     */
    public String getGender() {
        return gender;
    }

    /**
     * 设置
     * @param gender
     */
    public void setGender(String gender) {
        this.gender = gender;
    }

    public String toString() {
        return "Teacher{name = " + name + ", age = " + age + ", height = " + height + ", gender = " + gender + "}";
    }
}
public class Test5 {
    public static void main(String[] args) throws IOException, IllegalAccessException {
        Student s = new Student("张三", 18);
        Teacher t = new Teacher("zhs", 19, 177.5, "男");
        //saveObject(s)
        saveObject(t);
    }

    public static void saveObject(Object obj) throws IllegalAccessException, IOException {
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        BufferedWriter bw = new BufferedWriter(new FileWriter("day32-code\\src\\test5\\a.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();
    }
}

反射练习2

动态创建对象,即创建配置文件内容里的对象,并调用内容里的方法,而即使配置文件发生改变,程序也不用改变

配置文件:

classname=test6.Teacher
method=teach
public class Teacher {
    private String name;
    private double salary;

    public Teacher() {
    }

    public Teacher(String name, double 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 double getSalary() {
        return salary;
    }

    /**
     * 设置
     * @param salary
     */
    public void setSalary(double salary) {
        this.salary = salary;
    }

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

    public void teach() {
        System.out.println("老师在教书");
    }
}
public class Test6 {
    public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.读取配置文件中的信息
        Properties prop = new Properties();
        FileInputStream fis = new FileInputStream("day32-code\\src\\test6\\prop.properties");
        prop.load(fis);
        fis.close();

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

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

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

        //调用成员方法并运行
        Method method = clazz.getDeclaredMethod(methodName);
        method.setAccessible(true);
        method.invoke(o);
    }
}
;