深入了解Java中的反射机制(reflect)

 更新时间:2023年05月21日 08:37:09   作者:无声编码器  
Java的反射机制允许我们对一个类的加载、实例化、调用方法、操作属性的时期改为在运行期进行,这大大提高了代码的灵活度,本文就来简单讲讲反射机制的具体使用方法吧

Java的反射机制允许我们对一个类的加载、实例化、调用方法、操作属性的时期改为在运行期进行,这大大提高了代码的灵活度。但在运行期进行反射操作会消耗额外的资源与性能,所以要适度使用。

JVM(Java虚拟机)加载一个类有以下几种方式:

1、执行代码时,需要用到某个类,例如:Person p = new Person(); 时,这时候JVM 会加载 Person.class 。

2、通过反射机制中的:Class.forName(String className) 方法以字符串的形式加载指定的类,此方法只能寻找环境变量中配置的类路径中指定的类。

3、通过类加载器 ClassLoader 来加载指定的类,类加载器可以额外指定环境变量中没有指定的类路径,并从中寻找指定的类进行加载。

除了第一种方式外,剩下的两种都是基于反射机制动态的加载一个类,加载类的过程就是让 JVM 读取该类对应的 class 文件。当 JVM 读取一个类的 class 文件后,会实例化一个 Class 类的实例用于保存加载的这个类的信息。并且每个被加载的类只会进行一次加载过程,这意味着每个被 JVM 加载的类都会在 JVM 内部以一个 Class 类的实例进行保存,所以每个类有且只有一个 Class 类的实例与之对应。Class 也称为类对象,每个实例用于表示 JVM 加载的一个类,通过它可以获取其表示的类的相关信息,比如类的名字、有哪些属性、构造器以及所有方法,并且通过 Class 还可以实例化其表示的类。

Class 类 与 Method 类

  • Class 类:Class 类的实例表示正在运行的Java应用程序中的类和接口。Class 类没有公共构造函数,类对象是由Java虚拟机在加载类时自动构造的,通过调用类加载器中的defineClass方法来构造。
  • Method 类:Method 类是反射API中一个重要的类,其每一个实例表示某个类的一个具体方法,所反映的方法可以是类方法或实例方法(包括抽象方法)。通过 Method 可以获取到其表示的方法的相关信息,如方法名、返回值类型、参数类型、访问修饰符等。并且也可以通过 Method 类动态调用其表示的方法。

方法实例

public static Class<?> forName(String className)
                throws ClassNotFoundException

描述:

返回与具有给定字符串名称的类或接口关联的Class对象。

参数:

className -- 所需类的完全限定名称。

返回值:

具有指定名称的类的Class对象。

注意:

如果找不到类,抛出 ClassNotFoundException 异常。

public class Person {
    public String name;
    private Integer code;
    public Person() {
        System.out.println("无参构造方法");
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> aClass = Class.forName("Person");
        System.out.println(aClass);
    }
}
// 程序运行结果如下:
// class Person
public T newInstance()
        throws InstantiationException, IllegalAccessException

描述:

创建由该 Class 对象表示的类的新实例。该方法调用当前 Class 所表示的类的无参构造方法,所以该类必须有无参构造方法。

参数:

返回值:

由该 class 表示的类的新分配的实例。

注意:

  • 如果类或其无参构造函数不可访问,抛出 IllegalAccessException 异常。
  • 如果该类表示抽象类、接口、数组类、基元类型或void;或者如果该类没有无参构造函数;或者如果实例化由于某些其他原因而失败,抛出 InstantiationException 异常。
public class Person {
    public String name;
    private Integer code;
    public Person() {
        System.out.println("调用了无参构造方法");
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> aClass = Class.forName("Person");
        Person person = (Person)aClass.newInstance();
        System.out.println(person);
    }
}
// 程序运行结果如下:
// 调用了无参构造方法
// Person@29453f44
public Constructor<T> getConstructor(Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException

描述:

返回一个构造函数对象,该对象反映由该Class对象表示的类的指定公共构造函数。

参数:

parameterTypes -- Class对象的数组,这些对象按声明的顺序标识构造函数的形式参数类型。

返回值:

与指定的parameterTypes匹配的公共构造函数的Constructor对象。

注意:

  • 如果找不到匹配的方法,抛出 NoSuchMethodException 异常。
  • 如果访问被拒绝,抛出 SecurityException 异常。
public class Person {
    public String name;
    private Integer code;
    public Person(String name) {
        this.name = name;
        System.out.println("调用了有参构造方法");
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> aClass = Class.forName("Person");
        Constructor constructor = aClass.getConstructor(String.class);
        Person person = (Person)constructor.newInstance("阿刚");
        System.out.println(person.name);
    }
}
// 程序运行结果如下:
// 调用了有参构造方法
// 阿刚
// Class 类
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException

描述:

获取当前 Class 所表示的类定义的指定名字及参数列表的方法。

参数:

  • name -- 方法的名称。
  • parameterTypes -- 一组Class对象,这些对象按声明的顺序标识方法的形式参数类型。

返回值:

与指定的名称和参数匹配的此类的方法的Method对象。

注意:

  • 如果找不到匹配的方法,抛出 NoSuchMethodException 异常。
  • 如果名称为null, 抛出 NullPointerException 异常。
  • 如果访问被拒绝,抛出 SecurityException 异常。
// Method 类
public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException

描述:

在具有指定参数的指定对象上调用此 method 对象表示的基础方法。如果基础方法是静态的,则会忽略指定的 obj 参数,它可能为 null。

参数:

  • obj -- 如果通过该方法调用的是成员方法,因为成员方法属于对象,那么调用该方法时,使用该参数传递成员方法所属对象。如果过该方法调用的是静态方法,可以传递null。
  • args -- 方法的实际参数,若该方法无参,传入 null 即可。

注意:

  • 如果此Method对象正在强制执行Java语言访问控制,并且底层方法不可访问,抛出 IllegalAccessException 异常。
  • 如果方法是实例方法,并且指定的对象参数不是声明底层方法(或其子类或实现者)的类或接口的实例;或者如果实际参数和形式参数的数量不同;或者如果原始参数的展开转换失败;或者如果在可能的展开之后,无法通过方法调用转换将参数值转换为相应的形式参数类型; 抛出 IllegalArgumentException 异常。
  • 如果基础方法抛出异常,则抛出 InvocationTargetException 异常。
  • 如果指定的对象为null,并且该方法是实例方法,则抛出 NullPointerException 异常。
public class Person {
    public String name;
    private Integer code;
    public Person() {
        System.out.println("调用了无参构造方法");
    }
    public Person(String name) {
        this.name = name;
        System.out.println("调用了有参构造方法");
    }
    public  static String happy(){
        return "哈哈";
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
}
public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> aClass = Class.forName("Person");
        Object person =  aClass.newInstance();
        // Method是反射API中一个重要的类,其每一个实例表示某个类的具体方法
        // 调用 setName 方法
        Method setMethod = aClass.getDeclaredMethod("setName",String.class);
        setMethod.invoke(person,"阿全");
        // 调用 getName 方法
        Method getMethod = aClass.getDeclaredMethod("getName",null);
        System.out.println(getMethod.invoke(person,null));
        // 调用了静态方法
        Method happyMethod = aClass.getDeclaredMethod("happy",null);
        System.out.println(happyMethod.invoke(null,null));
    }
}
// 程序运行结果如下:
// 调用了无参构造方法
// 阿全
// 哈哈

以上就是深入了解Java中的反射机制(reflect)的详细内容,更多关于Java反射机制的资料请关注脚本之家其它相关文章!

相关文章

  • Java存储数据至Rredis之@RedisHash实现过程

    Java存储数据至Rredis之@RedisHash实现过程

    文章介绍了在项目启动时通过@RedisHash注解,将Java对象映射为Redis中的Hash结构,实现数据的自动加载与管理,具体步骤包括引入依赖、创建实体类、实现Repository,并完成增删查改操作
    2025-10-10
  • Java如何识别图片或扫描PDF中的文字详解

    Java如何识别图片或扫描PDF中的文字详解

    这篇文章主要介绍了Java如何识别图片或扫描PDF中文字的相关资料,介绍了Java中使用Spire.OCRforJava库来识别图片和扫描PDF文件中的文字,需要的朋友可以参考下
    2025-01-01
  • java bootclasspath的具体用法

    java bootclasspath的具体用法

    本文主要介绍了java bootclasspath的具体用法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • Java Atomic类及线程同步新机制原理解析

    Java Atomic类及线程同步新机制原理解析

    这篇文章主要介绍了Java Atomic类及线程同步新机制原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-07-07
  • Java详解使用线程池处理任务方法

    Java详解使用线程池处理任务方法

    java中经常需要用到多线程来处理,我们非常不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程,那样势必有创建及销毁线程耗费资源、线程上下文切换问题。同时创建过多的线程也可能引发资源耗尽的风险,这个时候引入线程池比较合理,方便线程任务的管理
    2022-05-05
  • 详解Spring MVC的拦截器与异常处理机制

    详解Spring MVC的拦截器与异常处理机制

    这篇文章主要为大家详细介绍了Spring MVC的拦截器与异常处理机制,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-02-02
  • SpringBoot执行有返回值的异步任务问题

    SpringBoot执行有返回值的异步任务问题

    这篇文章主要介绍了SpringBoot执行有返回值的异步任务问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-07-07
  • Mybatis-Plus更新操作时遇到的问题及解决方法

    Mybatis-Plus更新操作时遇到的问题及解决方法

    在MyBatis-Plus开启逻辑删除时,使用updateById更新逻辑删除字段时,可能会出现看起来执行了但实际上没有更新的问题,下面给大家介绍Mybatis-Plus更新操作时遇到的问题及解决方法,感兴趣的朋友跟随小编一起看看吧
    2026-01-01
  • IDEA为类和方法设置注解模板过程

    IDEA为类和方法设置注解模板过程

    本文主要讲述了在IntelliJ IDEA中创建类和方法注解模板的步骤与实际效果,并提供了两种方法注解模板的具体实现过程,通过自定义模板,用户可以自动化地生成类和方法的注释,提高开发效率
    2026-04-04
  • Java精品项目瑞吉外卖之员工新增篇

    Java精品项目瑞吉外卖之员工新增篇

    这篇文章主要为大家详细介绍了java精品项目-瑞吉外卖订餐系统,此项目过大,分为多章独立讲解,本篇内容为新增员工功能的实现,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-05-05

最新评论