Java反射中Class类与常用反射类库怎么配合使用

来源:Python编程网作者:孙悟空头衔:草根站长
导读:本期聚焦于小伙伴创作的《Java反射中Class类与常用反射类库怎么配合使用》,敬请观看详情。在调用私有方法时直接写字符串容易拼错导致运行时异常,这是反射使用的典型痛点。Class类是反射的入口,通过它可获取Method、Field、Constructor等对象。java.lang.reflect包提供了完整的反射类库,配合Class就能动态加载类、执行方法、修改字段。相比硬编译调用,反射让框架在运行期根据配置决定行为,但会带来性能损耗与安全检查开销。理解Class的forName、getDeclaredMethod等方法和reflect包中类的职责边界,能避免常见误用,比如忘记setAccessible造成的IllegalAccessException。

Java反射机制允许程序在运行期获取类的结构信息并动态调用其成员。Class类是这一切的起点,而java.lang.reflect包中的类库则提供了操作方法的工具。掌握二者如何配合,是理解Spring、MyBatis等框架底层原理的基础。

Java反射中Class类与常用反射类库怎么配合使用

一、Class类:反射的元数据入口

在Java中,每个加载到内存的类都有一个对应的Class对象,它由JVM在类加载时创建,保存了类的名称、父类、接口、构造器、方法和字段等信息。我们拿到Class对象后,才能进一步通过反射API探查和操作这个类。

获取Class对象主要有三种方式。第一种是使用类字面量,例如String.class,这种方式在编译期就确定类型且不会触发类的初始化;第二种是通过对象的getClass方法,适用于已经有实例的场景;第三种是使用Class.forName,它根据全限定名加载类并返回Class对象,很多框架读取配置文件时都采用这种方式。

// 方式一:类字面量
Class<String> c1 = String.class;

// 方式二:对象实例
String s = "";
Class<? extends String> c2 = s.getClass();

// 方式三:动态加载
try {
    Class<?> c3 = Class.forName("java.util.ArrayList");
    System.out.println(c3.getName());
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

二、java.lang.reflect包中的常用反射类库

java.lang.reflect包是Java标准库提供的反射工具集,核心类包括Field、Method、Constructor、Modifier和Array等。它们分别代表类的字段、方法、构造器、修饰符信息和数组操作能力。这些类通常由Class对象的方法返回,自身不负责查找,只负责承载结构与提供调用能力。

例如,Class.getDeclaredMethods返回Method数组,包含本类声明的所有方法;Class.getFields则返回public字段。Method类提供了invoke来执行方法,Field类提供了get和set来读写属性。下面代码展示如何通过Class与Method配合调用一个私有方法。

import java.lang.reflect.Method;

public class Demo {
    private void hello(String name) {
        System.out.println("hello " + name);
    }

    public static void main(String[] args) throws Exception {
        Class<Demo> clazz = Demo.class;
        // 获取声明的方法,包括private
        Method m = clazz.getDeclaredMethod("hello", String.class);
        // 私有方法必须设置可访问
        m.setAccessible(true);
        Demo obj = clazz.getDeclaredConstructor().newInstance();
        m.invoke(obj, "world");
    }
}

三、Class与反射类库的协作流程

典型协作流程是:先通过Class定位类型,再用Class提供的方法拿到reflect包中的对象,最后由这些对象执行具体操作。这种分工让Class专注于类型元数据检索,reflect类专注于行为调用,职责清晰。

以动态创建对象并赋值字段为例,先用Class.forName拿到类型,再用getDeclaredConstructor新建实例,接着用getDeclaredField取得Field对象并set值。整个过程没有在代码中写死具体类名,全部由字符串驱动,这就是许多IOC容器的工作缩影。

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

class User {
    private String name;
    public String toString() { return "User:" + name; }
}

public class Test {
    public static void main(String[] args) throws Exception {
        Class<?> clazz = Class.forName("User");
        Constructor<?> con = clazz.getDeclaredConstructor();
        Object u = con.newInstance();
        Field f = clazz.getDeclaredField("name");
        f.setAccessible(true);
        f.set(u, "tom");
        System.out.println(u);
    }
}

四、使用注意与性能考量

反射虽灵活,但每次调用都会进行安全检查并解析符号引用,比直接调用慢很多。在高频路径上应缓存Method、Field对象,避免反复查找。同时,setAccessible(true)会绕过私有保护,仅应在受控环境下使用,否则破坏封装。

另外,Class本身不提供调用能力,若误以为直接拿Class就能执行方法就会写出错误代码。明确Class负责“找”,reflect类负责“做”,才能写出健壮的反射逻辑。在模块化Java中,还需在module-info中开放包给反射,否则会抛出InaccessibleObjectException。

对比项Class类reflect类库
主要职责类型元数据检索成员操作与调用
典型方法forName, getDeclaredMethodinvoke, set, get
获取方式类加载产生由Class方法返回

五、小结

Class是反射体系的枢纽,reflect类库是延伸的工具手。理解二者边界与配合方式,能够帮助我们在不修改编译期代码的前提下实现高度灵活的运行期行为,也为阅读主流框架源码打下基础。

在实际项目中,建议将反射调用封装在工具类中,统一处理异常与缓存,减少对业务代码的侵入。这样既能享受动态能力,又能控制复杂度和性能风险。

Java反射Class类反射类库修改时间:2026-08-10 01:48:13

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。