目录

Java高级-04.反射-获取成员变量和方法对象并使用

目录

Java高级-04.反射-获取成员变量和方法对象并使用

一.获取类的成员变量

package com.njau.d2_reflect;



public class Cat {
    public static int a;
    public static final String COUNTRY = "中国";
    private String name;
    private int age;

    public Cat(String name, int age) {
        System.out.println("有参数构造器执行了!");
        this.name = name;
        this.age = age;
    }

    public Cat() {
        System.out.println("无参构造器执行了!");
    }

    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 "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

https://i-blog.csdnimg.cn/direct/d1980ca462f148f68d5e89632eb783d6.png

* public Field[] getFields()   获取类的全部成员变量(只能获取public修饰的) * public Field[] getDeclaredFields()  获取类的全部成员变量(只要存在就能拿到) * public Field getField()   获取类的某个成员变量(只能获取public修饰的) * public Field getDeclaredField()  获取类的全部成员变量(只要存在就能拿到)

返回回来的是一个Filed类型的对象。可以使用数组接收多个。

package com.njau.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Field;

/**
 * 目标:掌握获取类的成员变量
 * Class提供了从类中获取成员变量的方法
 * public Field[] getFields()   获取类的全部成员变量(只能获取public修饰的)
 * public Field[] getDeclaredFields()  获取类的全部成员变量(只要存在就能拿到)
 * public Field getField(String name)   获取类的某个成员变量(只能获取public修饰的)
 * public Field getDeclaredField(String name)  获取类的全部成员变量(只要存在就能拿到)
 * 获取到成员变量的作用:依然是赋值,取值
 * void set(Object obj,Object value)   赋值
 * Object get(Object obj)   取值
 * public void setAccessible(boolean flag)   设置为true,表示禁止检查访问控制(暴力反射)
 */

public class Test3Field {
    @Test
    public void testGetFields() throws Exception {
        // 1、反射第一步:首先获取到类Class对象
        Class c = Cat.class;

        // 2、public Field[] getFields()   获取类的全部成员变量(只能获取public修饰的)
//        Field[] fields = c.getFields();
        Field[] fields = c.getDeclaredFields();    // 获取类的全部成员变量(只要存在就能拿到)

        for (Field field : fields) {
            System.out.println(field.getName() + "--->" + field.getType());
        }

        // 3、public Field getField(String name)   获取类的某个成员变量(只能获取public修饰的)
        Field fName = c.getDeclaredField("name");
        System.out.println(fName.getName() + "--->" + fName.getType());    // name--->class java.lang.String

        // 4、public Field getDeclaredField(String name)  获取类的某个成员变量(只要存在就能拿到)
        Field fAge = c.getDeclaredField("age");
        System.out.println(fAge.getName() + "--->" + fAge.getType());   // age--->int
    }
}

https://i-blog.csdnimg.cn/direct/0d560780edd14716bc5f9cb73c8c0260.png

获取成员变量的作用:依然是赋值、取值

使用set进行赋值,但是赋值时必须要创建出该类的实例化对象,否则这个值又赋给谁呢?同样的,使用get方法时也要传入该类的实例化对象,否则不知道获取哪个对象的成员变量值。

注意:我们在获得构造器和成员变量的时候均不用setAccessible方法,而是在 使用 构造器实例化对象和使用成员变量赋值的时候,对于私有的构造器和成员变量才要使用setAccessible方法。成员方法也和上述一样。

package com.njau.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Field;

/**
 * 目标:掌握获取类的成员变量
 * Class提供了从类中获取成员变量的方法
 * public Field[] getFields()   获取类的全部成员变量(只能获取public修饰的)
 * public Field[] getDeclaredFields()  获取类的全部成员变量(只要存在就能拿到)
 * public Field getField()   获取类的某个成员变量(只能获取public修饰的)
 * public Field getDeclaredField()  获取类的全部成员变量(只要存在就能拿到)
 * 获取到成员变量的作用:依然是赋值,取值
 * void set(Object obj,Object value)   赋值
 * Object get(Object obj)   取值
 * public void setAccessible(boolean flag)   设置为true,表示禁止检查访问控制(暴力反射)
 */

public class Test3Field {
    @Test
    public void testGetFields() throws Exception {
        // 1、反射第一步:首先获取到类Class对象
        Class c = Cat.class;

        // 2、public Field[] getFields()   获取类的全部成员变量(只能获取public修饰的)
//        Field[] fields = c.getFields();
        Field[] fields = c.getDeclaredFields();    // 获取类的全部成员变量(只要存在就能拿到)

        for (Field field : fields) {
            System.out.println(field.getName() + "--->" + field.getType());
        }

        // 3、public Field getField(String name)   获取类的某个成员变量(只能获取public修饰的)
        Field fName = c.getDeclaredField("name");
        System.out.println(fName.getName() + "--->" + fName.getType());    // name--->class java.lang.String

        // 4、public Field getDeclaredField(String name)  获取类的某个成员变量(只要存在就能拿到)
        Field fAge = c.getDeclaredField("age");
        System.out.println(fAge.getName() + "--->" + fAge.getType());   // age--->int
    }

    @Test
    public void testSetAndGet() throws Exception {
        Class c = Cat.class;
        Cat cat = new Cat();
//        获取某个类的成员变量
        Field fName = c.getDeclaredField("name");
//        public void setAccessible(boolean flag)   设置为true,表示禁止检查访问控制(暴力反射)
        fName.setAccessible(true);   // 禁止访问控制权限
//        void set(Object obj,Object value)   赋值
        fName.set(cat, "招财猫");
//        Object get(Object obj)   取值
        String name = (String) fName.get(cat);
        System.out.println(name);
        System.out.println(cat);

        Field fAge = c.getDeclaredField("age");
//        public void setAccessible(boolean flag)   设置为true,表示禁止检查访问控制(暴力反射)
        fAge.setAccessible(true);
//        void set(Object obj,Object value)   赋值
        fAge.set(cat,3);
//        Object get(Object obj)   取值
        int age = (int) fAge.get(cat);
        System.out.println(age);
        System.out.println(cat);
    }
}

调用get方法时并不知道返回的成员变量类型,因此java官方为我们设定了Object类型。但是我们要将其进行强制转换。

二.获取类的成员方法

package com.njau.d2_reflect;



public class Cat {
    public static int a;
    public static final String COUNTRY = "中国";
    private String name;
    private int age;

    public Cat(String name, int age) {
        System.out.println("有参数构造器执行了!");
        this.name = name;
        this.age = age;
    }

    public Cat() {
        System.out.println("无参构造器执行了!");
    }

    public String getName() {
        return name;
    }

    private void run() {
        System.out.println("🐱跑的贼快~~");
    }

    public void eat() {
        System.out.println("🐱爱吃猫粮~~");
    }

    // 方法的重载
    private String eat(String name) {
        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 "Cat{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

https://i-blog.csdnimg.cn/direct/57a10ed3f549486ba28e6a8e477d150d.png

* Method[] getMethods()   获取类的全部成员方法(只能获取public修饰的) * Method[] getDeclaredMethods()   获取类的全部成员方法(只要存在就能获取) * Method[] getMethod(String name,Class … parameterTypes)   获取类的某个成员方法(只能获取public修饰的) * Method[] getDeclaredMethod(String name,Class … parameterTypes)   获取类的某个成员方法(只要存在就能获取)

首先我们要获取类的成员方法,就要先获取类对象。因此反射的第一步永远都是获取类对象。

package com.njau.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Method;

/**
 * 目标:获取类的成员方法
 * Method[] getMethods()   获取类的全部成员方法(只能获取public修饰的)
 * Method[] getDeclaredMethods()   获取类的全部成员方法(只要存在就能获取)
 * Method[] getMethod(String name,Class<?> ... parameterTypes)   获取类的某个成员方法(只能获取public修饰的)
 * Method[] getDeclaredMethod(String name,Class<?> ... parameterTypes)   获取类的某个成员方法(只要存在就能获取)
 * 成员方法的作用:依然是执行
 * public Object invoke(Object obj, Object ... args)   出发某个对象的该方法执行  Object obj代表类的某个实例对象
 * public void setAccessible(boolean flag)  设置为true,表示禁止检查访问控制(暴力反射)
 */
public class Test4Method {
    @Test
    public void testGetDeclaredMethods() throws Exception {
        // 1、反射第一步:首先获取Class对象
        Class c = Cat.class;

        // 2、获取类的全部成员方法
        Method[] methods = c.getDeclaredMethods();
        // 3、对所有成员方法进行遍历
        for (Method method : methods) {
            System.out.println(method.getName() + "--->" + method.getParameterCount()
                    + "--->" + method.getReturnType());
        }

        // 4、获得某个成员方法
        Method run = c.getDeclaredMethod("run");
        System.out.println(run.getName() + "--->" + run.getParameterCount()
                + "--->" + run.getReturnType());  // run--->0--->void

        Method eat = c.getDeclaredMethod("eat",String.class);
        System.out.println(eat.getName() + "--->" + eat.getParameterCount()
                + "--->" + eat.getReturnType());  // eat--->1--->class java.lang.String
    }
}

我们使用getDeclaredMethods()方法来获取类中的全部实例对象。然后用Method类型的数据对其进行封装。封装后我们进行遍历,在遍历时我们可以使用:

1.getName()方法获得该方法的方法名

2.getParameterCount()方法获得该方法的参数个数

3.getReturnType()方法获得该方法的返回值类型

我们使用getDeclaredMethod(String name,Class … parameterTypes)方法来获取类中的指定的实例对象。其中要获得指定的方法吗,就要在name字段指定方法名,在Class … parameterTypes字段指定参数类型。

通过反射获得成员方法的作用依然是执行

* public Object invoke(Object obj, Object … args)   出发某个对象的该方法执行  Object obj代表类的某个实例对象 * public void setAccessible(boolean flag)  设置为true,表示禁止检查访问控制(暴力反射)

我们可以在获得成员方法对象后通过invoke方法执行该成员方法。但是在使用invoke方法之前,我们首先要new一个该方法所在类的实例化对象,因为这个成员方法是该类的成员方法,是通过该类的实例化对象进行调用的。因此要先将该类实例化对象出来,再将该对象传入invoke方法里才能够进行调用。

package com.njau.d2_reflect;

import org.junit.Test;

import java.lang.reflect.Method;

/**
 * 目标:获取类的成员方法
 * Method[] getMethods()   获取类的全部成员方法(只能获取public修饰的)
 * Method[] getDeclaredMethods()   获取类的全部成员方法(只要存在就能获取)
 * Method[] getMethod(String name,Class<?> ... parameterTypes)   获取类的某个成员方法(只能获取public修饰的)
 * Method[] getDeclaredMethod(String name,Class<?> ... parameterTypes)   获取类的某个成员方法(只要存在就能获取)
 * 成员方法的作用:依然是执行
 * public Object invoke(Object obj, Object ... args)   出发某个对象的该方法执行  Object obj代表类的某个实例对象
 * public void setAccessible(boolean flag)  设置为true,表示禁止检查访问控制(暴力反射)
 */
public class Test4Method {
    @Test
    public void testGetDeclaredMethods() throws Exception {
        // 1、反射第一步:首先获取Class对象
        Class c = Cat.class;

        // 2、获取类的全部成员方法
        Method[] methods = c.getDeclaredMethods();
        // 3、对所有成员方法进行遍历
        for (Method method : methods) {
            System.out.println(method.getName() + "--->" + method.getParameterCount()
                    + "--->" + method.getReturnType());
        }

        // 4、获得某个成员方法
        Method run = c.getDeclaredMethod("run");
        System.out.println(run.getName() + "--->" + run.getParameterCount()
                + "--->" + run.getReturnType());  // run--->0--->void

        Method eat = c.getDeclaredMethod("eat",String.class);
        System.out.println(eat.getName() + "--->" + eat.getParameterCount()
                + "--->" + eat.getReturnType());  // eat--->1--->class java.lang.String

        Cat cat = new Cat();  // 创建一个猫对象
        run.setAccessible(true);   // 表示禁止检查访问控制(暴力反射)
        Object object = run.invoke(cat);  // 🐱跑的贼快~~
        System.out.println(object);  // null  没有返回值,就是null

        eat.setAccessible(true);
        String food = (String) eat.invoke(cat, "鱼儿");
        System.out.println(food);
    }
}

我们使用获取到的成员方法对象run调用invoke方法执行run方法,在调用invoke方法前我们实例化一个Cat类对象cat,并将该对象传入invoke方法中,又因为run方法没有参数,因此不需要传递参数。也没有返回值,因此返回值为null。java官方并不知道我们的方法返回值类型是什么,因此统一使用Object进行接收。

同样的,在调用eat的重载方法时,有一个参数String类型的,因此要传入一个字符串。且返回值是一个字符串,因此要使用String类型的变量接收并打印出来。

当我们在调用invoke进行方法的执行时,由于我们的方法在定义时都是用private修饰的,因此再调用invoke执行该方法时会出现权限不够,因此要使用setAccessible()方法将其设置为true。才能保证正常执行。

执行结果: