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

类和反射的机制

一、类

1.类的生命周期

1. 类的编译:通过 javac 命令将 .java 源文件编译成 .class 字节码文件。
2. 类的加载:类加载器(ClassLoader)将 .class 文件从硬盘加载到内存,形成“类对象”,包括加载、链接、初始化三个阶段。
3. 类的初始化和实例化:通过 new 关键字实例化类,创建具体对象。
4. 对象的生命周期:对象从创建到被垃圾回收器(GC)回收的整个过程。
5. 反射机制:允许在运行时动态加载类,扩展了类加载的灵活性。

二、 反射机制

Java 反射是指在运行时动态获取类的信息(如类名、方法、字段等)并操作类的能力。

三、反射的前提:获取 “类对象”

反射的所有操作,都必须基于一个核心载体 ——Class 类的对象(简称 “类对象”)。每个类在 JVM 中只会被加载一次,因此同一个类的类对象全局唯一。

1. 获取 Class 对象的三种方式

三种获取  Person  类的  Class  对象的方法

public class Test {public static void main(String[] args) throws ClassNotFoundException {// 1、硬盘阶段获取类对象Class class1 = Class.forName("com.qcby.reflect.Person");// 2、类阶段Class class2 = Person.class;// 3、对象阶段Person person = new Person();Class class3 = person.getClass();System.out.println(class1 == class2);System.out.println(class2 == class3);}
}

2.获取成员变量


2.1.读写变量值:set () 与 get ()

语法:
写值:field.set(对象实例, 变量值)(为指定对象的该变量赋值)
读值:field.get(对象实例)(获取指定对象的该变量值)
关键注意:若变量是 private 私有权限,直接读写会抛出 IllegalAccessException,需先调用 field.setAccessible(true) 开启 “暴力反射”,强制跳过权限检查。

2.2.应用

Person person = new Person();
// 获取类对象
Class pclass = Class.forName("com.qcby.reflect.Person");// 通过类对象获取成员变量们
Field[] fields = pclass.getDeclaredFields();
for (Field item : fields) {System.out.println(item);
}Field field_age = pclass.getDeclaredField("age");
System.out.println(field_age);Field[] public_fields = pclass.getFields();
for (Field item : public_fields) {System.out.println(item);
}Field field_from = pclass.getField("from");
System.out.println(field_from);// 获取和设置
field_from.set(person, "中国");
field_age.setAccessible(true);
field_age.set(person, 20);System.out.println(field_age.get(person));
System.out.println(field_from.get(person));
System.out.println(person);
// 1. 创建 Person 对象实例
Person person = new Person();
// 2. 获取类对象
Class pClass = Class.forName("reflect.Person");// 3. 获取所有成员变量(含 private)
Field[] allFields = pClass.getDeclaredFields();
for (Field field : allFields) {System.out.println(field); // 输出:private java.lang.String reflect.Person.name、private int reflect.Person.age、public java.lang.String reflect.Person.from
}// 4. 获取指定私有变量 name(需暴力反射)
Field nameField = pClass.getDeclaredField("name");
nameField.setAccessible(true); // 开启暴力反射,突破 private 限制
nameField.set(person, "赵嘉成"); // 赋值
System.out.println(nameField.get(person)); // 取值,输出:赵嘉成// 5. 获取指定公共变量 from(无需暴力反射)
Field fromField = pClass.getDeclaredField("from");
fromField.set(person, "中国"); // 直接赋值
System.out.println(person); // 输出:Person [name=赵嘉成, age=0, from=中国]

3.获取成员方法

3.1.执行方法:invoke ()

语法:method.invoke(对象实例, 方法参数值...)

若方法是静态方法(static),对象实例可传 null;
若方法无参数,参数值部分可省略或传空数组;
若方法有返回值,invoke() 会返回该值(需强转)。

权限注意:私有方法需先调用 method.setAccessible(true) 开启暴力反射。

3.2.执行代码

// 获取所有方法(包括私有)
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {System.out.println(method);
}// 调用私有方法
Method runMethod = clazz.getDeclaredMethod("run");
runMethod.setAccessible(true);
runMethod.invoke(person); // 执行方法

4.获取构造方法

构造方法的反射操作,核心是 “获取构造器” 和 “创建对象”(替代 new 关键字),支持通过无参 / 有参构造器创建实例。

返回类型方法签名(含形参)获取范围典型用途
Constructor<?>[]getDeclaredConstructors()所有构造器(包括 private)暴力反射,想拿到任意访问修饰符的构造器
Constructor<T>getDeclaredConstructor(Class<?>... parameterTypes)指定一个构造器(包括 private)暴力反射,精确匹配形参列表
Constructor<?>[]getConstructors()仅 public 构造器正常反射,只关心公开构造器
Constructor<T>getConstructor(Class<?>... parameterTypes)指定一个 public 构造器正常反射,精确匹配形参列表且为 public

4.1 创建对象newInstance ()

语法:constructor.newInstance(构造参数值...)
无参构造器:参数值部分可省略,直接 constructor.newInstance();
有参构造器:需传入与参数列表匹配的参数值;
私有构造器:需先调用 constructor.setAccessible(true) 开启暴力反射。

// 1. 拿所有构造器(含 private)
Constructor<?>[] all = clazz.getDeclaredConstructors();// 2. 拿指定 private 构造器(如 Person(String, int))
Constructor<Person> c1 = clazz.getDeclaredConstructor(String.class, int.class);
c1.setAccessible(true);          // 暴力反射
Person p1 = c1.newInstance("Tom", 20);// 3. 拿所有 public 构造器
Constructor<?>[] pub = clazz.getConstructors();// 4. 拿指定 public 无参构造器
Constructor<Person> c2 = clazz.getConstructor();
Person p2 = c2.newInstance();

四、其他配置

1.步骤拆解与代码

创建配置文件(refconfig.properties):

# 配置要加载的类(全类名)
reflect.className=reflect.Person
# 配置要调用的方法名
reflect.methodName=getAge

2.获取类的基本信息

需求API示例结果
全限定名(包 + 类)clazz.getName()com.qcby.reflect.Person
简单类名clazz.getSimpleName()Person
包名clazz.getPackage().getName()com.qcby.reflect
父类clazz.getSuperclass()class java.lang.Object
实现的接口数组clazz.getInterfaces()[interface java.io.Serializable]
修饰符(public/private/…)Modifier.toString(clazz.getModifiers())public
是否为接口clazz.isInterface()FALSE
是否为数组clazz.isArray()FALSE
是否为枚举clazz.isEnum()FALSE
是否为注解clazz.isAnnotation()FALSE
是否为基本类型clazz.isPrimitive()FALSE

3.常见问题

​​1.反射能修改final字段吗?​​

可以,但需要先调用setAccessible(true)。

​​2.反射如何获取父类的方法?

​​使用getSuperclass()和getDeclaredMethods()。

3.​​反射为什么慢?​​

反射调用需要检查访问权限、动态解析方法名,无法被JIT优化。

http://www.xdnf.cn/news/19259.html

相关文章:

  • Redis桌面客户端
  • Windows驱动开发与双机调试环境[驱动开发环境配置高阶]
  • 使用 Ansible 和 Azure Pipelines 增强您的 DevOps
  • Qt实战:如何打开摄像头并实现视频的实时预览
  • 2025年09月计算机二级Java选择题每日一练——第十二期
  • macOs上ffmpeg带入libx264库交叉编译
  • 【龙泽科技】汽车电气故障诊断仿真教学软件【迈腾380TSI】
  • WebGIS视角:体感温度实证,哪座“火炉”火力全开?
  • centos7中MySQL 5.7.32 到 5.7.44 升级指南:基于官方二进制包的原地替换式升级
  • xAI发布全新编码模型 grok‑code‑fast‑1!
  • Kafka 消费模型
  • Qt 窗口 - 3
  • 操作系统-虚拟内存篇
  • 机器学习中的欠拟合与过拟合
  • 2025年如何批量下载雪球帖子和文章导出pdf?
  • 每日Java并发面试系列(5):基础篇(线程池的核心原理是什么、线程池大小设置为多少更合适、线程池哪几种类型?ThreadLocal为什么会导致内存泄漏?)
  • web渗透PHP反序列化漏洞
  • 设计模式 - 静态工厂模式 + 策略模式,
  • 【一】Django框架版本介绍
  • k8s 定时任务需求模板
  • 手动安装的node到nvm吧版本管理的过程。
  • GaussDB生产扩容引起的PANIC问题处理案例
  • HarmonyOS元服务开发
  • HarmonyOS三方库的使用
  • 计算机毕业设计 java 在线学习系统 基于 Java 的在线教育平台 Java 开发的学习管理系统
  • MongoDB 源码编译与调试:深入理解存储引擎设计 内容详细
  • 【办公类-39-06】20250830通义万相水果图(万相2.1专业Q版线描风格+万相专业2.2默认简笔画效果)
  • 淘宝利用商品关键词获取商品信息指南
  • GRPO(组相对策略优化):大模型强化学习的高效进化
  • 最强分布式锁工具:Redisson