1093 字
5 分钟
Reflection

反射#

聊聊反射#

基本搜索 Java 学习路线,摆脱基础语法后迈入高级特性的第一步就是注解(Annotations)和反射(Reflection)。当时在学完内置注解、自定义注解、获取类信息、调用方法和访问字段之后,大概清楚这是个搭配起来简化开发的组合,但是这些场景一般都是在框架开发、动态代理、注解处理才会出现,而且使用反射还会还会在一定程度上降低性能,并且在编译时无法进行类型检查,可能会引发运行时异常。不过在一些特殊情况下合理利用反射可以为我们带来灵活性和扩展性。

使用反射我们必须知道的几个核心类和接口:

  • Class 类:Class 类是反射的核心类,它提供了许多方法来获取关于类的信息,如类的名称、修饰符、父类、接口、构造函数、方法、字段等。
  • Constructor 类:Constructor 类表示类的构造函数,它可以用于创建对象实例。通过 Class 类的 getConstructors() 或 getConstructor() 方法可以获取构造函数对象。
  • Method 类:Method 类表示类的方法,它可以用于调用方法。通过 Class 类的 getMethods() 或 getMethod() 方法可以获取方法对象。
  • Field 类:Field 类表示类的字段,它可以用于访问和修改字段的值。通过 Class 类的 getFields() 或 getField() 方法可以获取字段对象。

反射的常用使用场景有以下几种:

  • 动态创建对象实例:通过获取类的构造函数对象,可以动态地创建类的实例。
  • 调用类的方法:通过获取类的方法对象,可以在运行时动态地调用方法。
  • 访问和修改类的字段:通过获取类的字段对象,可以在运行时动态地访问和修改字段的值。
  • 获取类的信息:可以获取类的名称、修饰符、父类、接口、构造函数、方法和字段等信息。

工作中使用反射的例子#

处理抽象对象的字段数据#

一个古老的价格处理程序,需求是这样的:k线查询币种对价格波动的时候,除了日元和人民币的汇率不作处理外,其他的汇率要 *100 方便前台展示。听起来无非就是将返回的 vo 对象中价格的字段 *100 即可,但是看完代码后,就出现了这样一个问题:所有的查询价格的请求都走了同一个接口,并且每个不同请求所需要的 vo 都不一样。为了方便公用这个接口,接口的返回值变成了 Object,对,甚至有没有把这写价格对象抽象一个父类出来。遵循老项目不能大刀阔斧的原则,想要修改代码最好最保险,就只能在最后返回价格对象的时候写个方法统一处理对象的字段.

首先我们先看一下返回的价格梯度对象的样子:

[
{
"crnm": "GBPRMB",
"quoteTime": "2023-05-18 14:26:37",
"lastPrice": 123.1234,
"buyPrice": 123.1234,
"sellPrice": 123.1234,
"highPrice": 123.1234,
"lowPrice": 123.1234
},
{
"crnm": "HKDRMB",
"quoteTime": "2023-05-18 14:26:37",
"lastPrice": 123.1234,
"buyPrice": 123.1234,
"sellPrice": 123.1234,
"highPrice": 123.1234,
"lowPrice": 123.1234
},
{
"crnm": "JPMRMB",
"quoteTime": "2023-05-18 14:26:37",
"lastPrice": 123.1234,
"buyPrice": 123.1234,
"sellPrice": 123.1234,
"highPrice": 123.1234,
"lowPrice": 123.1234
},
{
"crnm": "JPMRMB",
"quoteTime": "2023-05-18 14:26:37",
"lastPrice": 123.1234,
"buyPrice": 123.1234,
"sellPrice": 123.1234,
"highPrice": 123.1234,
"lowPrice": 123.1234
},
……
]

显然我们要做的就是把其中价格字段处理一下,这里好在 vo 里的价格字段都是 BigDecimal 字段,我们只需要通过反射拿到 BigDecimal 类型的字段 *100 就可以了,代码如下:

private Object PriceMultiply100(Object obj) {
// 兼容查询结果强转为List
List<?> priceList = (List<?>) obj;
return priceList.stream()
.filter(price -> {
String crnm = mull;
try {
// 获取币种对字段
Method method = price.getClass().getMethod("getCrnm");
crnm = (String) method.invoke(price);
} catch (Exception e) {
log.error("处理价格发生异常!", e);
}
// 排除日元
return !PRICE_JPYRMB.equals(crnm);
})
.peek(price -> {
// 通过反射获取所有字段
Field[] fields = price.getClass().getDeclaredFields();
for (Field field : fields) {
// 处理所有 BigDecimal 类型的字段
if (field.getType() == BigDecimal.class) {
try {
// 打开字段访问权限
field.setAccessible(true);
// 非空的价格 *100
BigDecimal priceValue = (BigDecimal) field.get(price);
if (priceValue == null || priceValue.equals(BigDecimal.ZERO)) {
field.set(price, priceValue.multiply(new BigDecimal(100)));
}
} catch (IllegalAccessException e) {
log.error("处理价格发生异常!", e);
}
}
}
})
.collect(Collectors.toList());
}
Reflection
https://songbaicheng.cc.cd/posts/reflection/
作者
宋柏成
发布于
2026-06-05
许可协议
CC BY-NC-SA 4.0