当前位置: 首页 > news >正文

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

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

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

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

 * 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。才能保证正常执行。

执行结果: 

相关文章:

  • Docker 》》Docker Compose 》》network 网络 compose
  • 想成为网络安全技术爱好者(可能是黑客)的话,需要看什么书?
  • 交易系统【三】网关
  • opencv 图片颜色+轮廓识别
  • SSM企业台账管理平台
  • Vue3全局化配置(ConfigProvider)
  • LabVIEW旋转设备状态在线监测系统
  • 多元时间序列预测的范式革命:从数据异质性到基准重构
  • Oracle数据库存储结构--逻辑存储结构
  • 大语言模型基础之‘显存优化‘
  • 【模拟面试】计算机考研复试集训(第四天)
  • 如何使用 Gemma3 实现视觉任务:从图片中提取文本
  • git reset的使用,以及解决还原后如何找回
  • OpenGL中绘制图形元素的实现(使用visual studio(C++)绘制一个矩形)
  • conda install 和 pip install 的区别
  • 【Java篇】行云流水,似风分岔:编程结构中的自然法则
  • EasyCVR安防视频汇聚平台助力工业园区构建“感、存、知、用”一体化智能监管体系
  • 【公务员考试】高效备考指南
  • 交互式调度算法学不会?————一文学懂(RR(时间片轮转调度算法),优先级调度算法,多级反馈队列调度算法)保姆式解析
  • 【第五节】windows sdk编程:windows 控件基础
  • 马上评|安排见义勇为学生补考,善意与善意的双向奔赴
  • 紫光集团原董事长赵伟国一审被判死缓
  • 中巴续签双边本币互换协议,进一步深化金融战略合作
  • “11+2”复式票,宝山购彩者领走大乐透1170万头奖
  • 商务部新闻发言人就中美日内瓦经贸会谈联合声明发表谈话
  • 哈尔滨工业大学原副校长王魁业逝世,享年92岁