Java 通过反射获取方法与变量

2023-05-16

0、反射技术

反射技术是Java生态中的重要内容,在Spring以及其他框架中得到了广泛的应用。

有了反射技术,我们可以在程序运行的过程中:

  • 构建任意一个类的对象,

  • 了解任意一个对象所属的类,

  • 获悉任意一个类中的所有成员变量和方法,

  • 调用任意一个类中的属性和方法。

1、获取方法

1.1、创建实体类

实体类中包含私有方法、公有方法、私有变量、公有变量。

public class Student {
    private String name;
    private Integer age;
    public String className;

    public Student() {
    }

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

    public Student(Integer age) {
        this.age = age;
    }

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

    private void getAge(){
        System.out.println("这是一个私有方法");
    }

    public void getName(){
        System.out.println("这是一个公有方法");
    }

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

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setClassName(String className) {
        this.className = className;
    }
}

1.1、获取构造方法

1.1.1 获取类中的所有构造方法

首先需要通过上一篇文章中提到的方法,获取到 class对象,再通过 getDeclaredConstructors() 获取到该类下所有构造方法。

import java.lang.reflect.Constructor;

public class Test {
    public static void main(String[] args) {
        Class<Student> student = Student.class;
        Constructor<?>[] constructors = student.getDeclaredConstructors();

        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }
    }
}

输出的结果如下:

public com.reflect.Student(java.lang.String,java.lang.Integer)

public com.reflect.Student(java.lang.Integer)

private com.reflect.Student(java.lang.String)

public com.reflect.Student()

从输出的结果中,可以看到:实体类中四个构造方法都被获取到了,包括一个私有构造方法。及构造方法中的参数列表也能被取出来。

1.1.2 获取所有公有构造方法

不同于获取所有构造方法的反射方法,这里使用 getConstructors() 即可。

import java.lang.reflect.Constructor;

public class Test {
    public static void main(String[] args) {
        Class<Student> student = Student.class;
        Constructor<?>[] constructors = student.getConstructors();

        for (Constructor constructor : constructors){
            System.out.println(constructor);
        }
    }
}

输出如下:

public com.reflect.Student(java.lang.String,java.lang.Integer)

public com.reflect.Student(java.lang.Integer)

public com.reflect.Student()

没有获取到类中类型为 private 的构造方法,仅有 public 方法。

1.1.3 根据参数列表,获取对应的构造方法

如果我们想要根据参数列表,获取到特定的构造方法时,可以使用 getDeclaredConstructor() 方法,方法中指明构造方法需要的参数:

  • 所有参数,必须使用 class 对象;
  • 参数的顺序应和构造方法中的顺序一致;
  • 要获取无参构造方法,可以输入 null 作为参数,或为空;
  • 这种方式可能会产生方法找不到的异常,因此需要对异常进行捕获或抛出。
import java.lang.reflect.Constructor;

public class Test {
    public static void main(String[] args) {
        try {
            Class<Student> student = Student.class;
            //获取私有构造方法
            Constructor<?> constructor = student.getDeclaredConstructor(String.class);
            System.out.println(constructor);
            //获取公有构造方法
            Constructor<?> constructor2 = student.getDeclaredConstructor(String.class, Integer.class);
            System.out.println(constructor2);
            //获取无参构造方法
            Constructor<?> constructor3 = student.getDeclaredConstructor(null);
            System.out.println(constructor3);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

输出结果为

private com.reflect.Student(java.lang.String)

public com.reflect.Student(java.lang.String,java.lang.Integer)

public com.reflect.Student()

  • 如果只想获取 public 类型的构造方法,可以使用 getConstructor() 方法,当对应的构造方法为 private 时,会报异常 java.lang.NoSuchMethodException
  • 根据参数列表没有找到对应的方法,程序会报异常 java.lang.NoSuchMethodException

1.2、获取普通方法

1.2.1 获取所有普通方法

使用class对象的 getDeclaredMethods() ,可以获取当前类下所有普通方法(非构造方法)。

import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) {
        Class<Student> student = Student.class;
        //获取所有方法
        Method[] declaredMethods = student.getDeclaredMethods();
        for (Method method : declaredMethods){
            System.out.println(method);
        }
    }
}

输出结果为

public void com.reflect.Student.getName()

public void com.reflect.Student.setName(java.lang.String)

private void com.reflect.Student.getAge()

public void com.reflect.Student.setAge(java.lang.Integer)

public void com.reflect.Student.setClassName(java.lang.String)

类型为 private 和 public 的方法,都被获取到了。

1.2.2 获取所有公有的普通方法

使用class对象的 getMethods() ,可以获取当前类及其所有父类下所有被 public 修饰的普通方法(非构造方法)。

import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) {
        Class<Student> student = Student.class;
        //获取所有方法
        Method[] declaredMethods = student.getMethods();
        for (Method method : declaredMethods){
            System.out.println(method);
        }
    }
}

输出结果中,包含了 Student 类及默认父类 Object 类下所有由 public 修饰的方法。

public void com.reflect.Student.getName()

public void com.reflect.Student.setName(java.lang.String)

public void com.reflect.Student.setAge(java.lang.Integer)

public void com.reflect.Student.setClassName(java.lang.String)

public final void java.lang.Object.wait() throws java.lang.InterruptedException

public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException

public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException

public boolean java.lang.Object.equals(java.lang.Object)

public java.lang.String java.lang.Object.toString()

public native int java.lang.Object.hashCode()

public final native java.lang.Class java.lang.Object.getClass()

public final native void java.lang.Object.notify()

public final native void java.lang.Object.notifyAll()

1.2.3 根据指定方法名及参数列表,获取指定方法

  • 如果要获取的方法为 public 时,使用 getMethod() 方法;

  • 如果想要获取私有方法时,需要使用 getDeclaredMethod() 方法。

  • 因为存在同名方法,需要在getMethod()方法中第一个参数指定要获取的方法名,后边为参数列表;

  • 无参方法时,参数列表可以没有,或使用 null 表示;

  • 因为可能存在方法找不到的情况,所以这里需要对异常进行处理或抛出;

  • 当使用getMethod()获取 private 修饰的方法时,也会抛出方法找不到的异常。

import java.lang.reflect.Method;

public class Test {
    public static void main(String[] args) {
        Class<Student> student = Student.class;
        try {
            //获取带参方法
            Method method = student.getMethod("setAge", Integer.class);
            System.out.println(method);
            //获取无参方法
            Method method2 = student.getMethod("getName", null);
            System.out.println(method2);
            //获取无参方法
            Method method3 = student.getMethod("getName");
            System.out.println(method3);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

输出结果

public void com.reflect.Student.setAge(java.lang.Integer)

public void com.reflect.Student.getName()

public void com.reflect.Student.getName()

2、获取成员变量

获取所有成员变量

import java.lang.reflect.Field;

public class Test {
    public static void main(String[] args) {
        Class<Student> student = Student.class;
        Field[] declaredFields = student.getDeclaredFields();
        for (Field field: declaredFields){
            System.out.println(field);
        }
    }
}

输出结果

private java.lang.String com.reflect.Student.name

private java.lang.Integer com.reflect.Student.age

public java.lang.String com.reflect.Student.className

3、获取类的其他信息

3.1、获取类名

public class Test {
    public static void main(String[] args) {
        Class<Student> student = Student.class;
        System.out.println(student.getName());
    }
}

获取类名其实有多种方式:

要么是通过类名获取,

或者通过对象获取,

或者指定类的全路径获取。

3.2、获取包名

可以拿到该类所在的包的全路径信息。

public class Test {
    public static void main(String[] args) {
        Class<HighSchoolStudent> student = HighSchoolStudent.class;
        Package aPackage = student.getPackage();
        System.out.println(aPackage);
    }
}

3.3、获取父类

public class Test {
    public static void main(String[] args) {
        Class<HighSchoolStudent> student = HighSchoolStudent.class;
        Class<? super HighSchoolStudent> superclass = student.getSuperclass();
        System.out.println(superclass);
    }
}

这种方式只能拿到该类的直接父类,如果想要获取所有父类,可以在拿到父类后循环遍历,直到父类为 Object 为止。

public class Test {
    public static void main(String[] args) {
        Class<ArrayList> arrayListClass = ArrayList.class;
        Class superclass = arrayListClass.getSuperclass();
        System.out.println(superclass);

        while (! "java.lang.Object".equals(superclass.getName())) {
            superclass = superclass.getSuperclass();
            System.out.println(superclass);
        }
    }
}

输出:

class java.util.AbstractList

class java.util.AbstractCollection

class java.lang.Object

3.4、获取实现的所有接口

该方法可以获取到该类实现的所有接口。

import java.util.ArrayList;

public class Test {
    public static void main(String[] args) {
        Class<ArrayList> arrayListClass = ArrayList.class;
        Class<?>[] interfaces = arrayListClass.getInterfaces();
        for(Class clazz: interfaces){
            System.out.println(clazz.getName());
        }
    }
}

输出如下:

java.util.List

java.util.RandomAccess

java.lang.Cloneable

java.io.Serializable

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java 通过反射获取方法与变量 的相关文章

随机推荐

  • Retrofit 使用

    Retrofit 使用 Retrofit 官网导入依赖库请求数据 xff08 以 玩Android 为例 xff0c 官方文档为 github 接口 xff1a https api github com xff09 数据请求前提getpos
  • Retrofit2 源码分析

    Retrofit2 源码分析 整体流程 xff08 以异步请求为例 xff09 源码分析总结 整体流程 xff08 以异步请求为例 xff09 通过建造者模式创建 Retrofit 对象Retrofit 对象通过 create 方法 xff
  • jar文件双击不能打开

    注册表 在Windows开始菜单的搜索框中输入 regedit xff0c 在上方搜索出的文件regedit上点击鼠标右键 xff0c 在弹出的菜单中选择 以管理员身份运行 在注册表编辑器中 xff0c 找到 HKEY CLASSES RO
  • 深入理解JS中的变量作用域

    在 JS 当中一个变量的作用域 xff08 scope xff09 是程序中定义这个变量的区域 变量分为两类 xff1a 全局 xff08 global xff09 的和局部的 其中全局变量的作用域是全局性的 xff0c 即在 JavaSc
  • SystemUI返回键手势和launcher上滑手势

    背景描述 最近修改bug和需求 xff0c 接触到系统手势这一块 xff0c 发现是一个薄弱点 xff0c 以前只是简单知道 xff0c 没有深入了解 手势这一块涉及的模块和流程比较多 xff0c 记录一下别人写的比较好的文章参考一下 初步
  • Android Studio 展开、折叠代码块快捷键

    展开 折叠代码块的方法 xff1a 折叠单个方法 xff1a 34 ctrl 34 43 34 34 展开单个方法 xff1a 34 ctrl 34 43 34 43 34 折叠全部方法 xff1a 34 ctrl 34 43 34 shi
  • Android Studio 重写父类方法的快捷键

    快速重写父类方法的快捷键 xff1a ctrl 43 o
  • 门面(外观)模式和代理模式区别

    本文只讲门面模式和代理模式的区别 今天用旅游吃饭来区分下门面模式和代理模式 门面模式是给用户提供一种服务 xff0c 就相当于我们的饭店 xff0c 可以给顾客提供美味的食物 代理模式是根据用户的需求 xff0c 提供解决该需求的方案 xf
  • 传输层TCP的流量控制和拥塞控制(图文详解)

    TCP的流量控制和拥塞控制 TCP流量控制流量控制中的死锁问题 x1f512 持续计时器 TCP的拥塞控制增加资源能解决拥塞吗 xff1f 拥塞往往会趋于恶化拥塞控制方法慢开始和拥塞避免慢开始拥塞避免 快重传和快恢复快重传快恢复 TCP流量
  • 数据链路层的子层MAC层(图文详解)

    数据链路层的子层MAC层 MAC层MAC层的硬件地址单站地址 xff0c 组地址 xff0c 广播地址全球管理与本地管理适配器检查MAC地址 MAC帧的格式 MAC层 MAC不是物理层 xff01 MAC不是物理层 xff01 MAC不是物
  • 补码一位乘法(Booth算法)和补码二位乘法详解

    文章目录 补码一位乘法补码二位乘法布斯算法的硬件实现 A D Booth提出了一种算法 xff1a 相乘二数用补码表示 xff0c 它们的符号位与数值为一起参与乘法运算的过程 xff0c 直接得出用补码表示的乘法结果 xff0c 且正数和负
  • 计算机原理中的字,位扩展,都给老子进来学,看不懂算我输!

    文章目录 涉及到的几个概念地址线与数据线 字扩展与位扩展 涉及到的几个概念 MDR xff1a 数据寄存器 xff0c 用来存入内存中读入 写出的信息 MAR xff1a 地址寄存器 xff0c 用来存放当前CPU访问的内存单元地址 地址线
  • 计算机组成原理中指令的四个工作周期

    文章目录 执行过程取指周期带有间址寻址的指令周期带有中断的指令周期 间指周期执行周期中断周期 执行过程 执行过程 xff1a 在取址周期后 xff0c 需要判断是否有间址周期 xff0c 如果没有就进入到了执行周期 xff0c 在执行周期过
  • Uncaught TypeError: $(...).modal is not a function

    项目场景 xff1a ssm框架配合bootstrap和AJAX xff0c 点击按钮弹出模态框 问题描述 xff1a Uncaught TypeError modal is not a function 原因分析 xff1a 没有引入bo
  • Lock锁及获取锁的四种方法

    为什么使用LOCK xff1f LOCK锁LOCK锁的上锁与解锁 为什么使用LOCK xff1f 传统的Synchronized锁有非常多的缺点 xff1a 锁的唤醒和阻塞代价较高 xff0c 线程的阻塞和唤醒 xff0c 操作系统需要在用
  • Chrome浏览器无法安装插件的解决办法

    国内不翻墙情况下 xff0c 无法正常登录谷歌账户 无法访问谷歌应用商店 xff0c 无法同步个人数据和安装使用各类插件 本文解决方法 xff1a 开发模式安装 步骤 xff1a 1 将xxx crx插件的扩展名改成 zip或者 rar并解
  • java8的ConcurrentHashMap为何放弃分段锁,为什么要使用CAS+Synchronized取代Segment+ReentrantLock

    原文地址 xff1a https cloud tencent com developer article 1509556 今天突然被一个同事问到java8为何放弃分段锁 xff0c 于是花了点时间针对这个问题进行了小小的总结 jdk1 7分
  • 8-17小记

    Comparator比较器的使用 435 无重叠区间 力扣 xff08 LeetCode xff09 leetcode cn com 给定一个区间的集合 xff0c 找到需要移除区间的最小数量 xff0c 使剩余区间互不重叠 注意 可以认为
  • Java关键字小记

    Static静态内部类静态变量和方法导包静态代码块 final用来修饰数据用来修饰方法参数修饰方法修饰类 abstractabstract类abstract方法 extendsthrow和throwsvolatile 本篇是Java关键字的
  • Java 通过反射获取方法与变量

    0 反射技术 反射技术是Java生态中的重要内容 xff0c 在Spring以及其他框架中得到了广泛的应用 有了反射技术 xff0c 我们可以在程序运行的过程中 xff1a 构建任意一个类的对象 xff0c 了解任意一个对象所属的类 xff