1. 什么是反射?
反射主要是指程序可以访问,检测和修改它本身的状态或行为的一种能力。
初读概念可能难以知道反射有什么作用。那我们接着往下看。
2. 反射有何用途?
Java中的反射是一种强大的工具,它能够创建灵活的代码,这些代码可以在运行时装配,无须在组件之间进行链接。
当我们从数据库中查询数据,并返回了一个ResultSet,但我们需要将ResultSet中的数据转成我们需要的List形式。常规的做法是遍历ResultSet,并在遍历体中将值赋给List。若是我们的数据表较少,并且查询的字段也足够少,我们勉强能接受这种“笨”方法。若是表很多并且一张表中有多达三四十个字段呢?那我们得写多少遍历?一个遍历中得写多少类似于rs.getXX("字段名")这样的代码?
我们既然知道数据库中返回的是什么字段,并且基本与我们的某个实体类属性相吻合,我们能否让他们自己去匹配呢?
答案当然是可以的,我们用JAVA的反射机制就可以实现这一功能。用反射创建灵活的代码!
我们需要一个可以在运行时将ResultSet中的一行结果与我们的目标实体类相互匹配,将相匹配的字段自动从当前ResultSet行填充到实体类中,若字段名不匹配则跳过,并依次循环添加到List中。这样我们就可以运用反射功能完成数据的自动填充。
我们对ResultSet进行遍历并将他的列明存入一个List<String>:
/**
* 获取ResultSet各列名
*
* @param rs
* @return
* @throws SQLException
*/
private List<String> getColumnNames(ResultSet rs) throws SQLException {
int count = rs.getMetaData().getColumnCount();
// String[] columnName = new String[count];
List<String> columnName = new ArrayList<>();
for (int i = 1; i <= count; i++) {
columnName.add(rs.getMetaData().getColumnName(i));
}
return columnName;
}
接下来我们需要用ResultSet的列名与我们需要返回的实体类属性相匹配,已知实体类类名XX.getClass(),需要返回什么类型我们不知道,用泛型T来代替。方法申明如下:
<span style="white-space:pre"> </span>public <T> List<T> toList(ResultSet rs, Class<T> clazz)
获取T类型字段:
try {
t = clazz.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// 获取T类型各字段
Field[] t_fields = t.getClass().getDeclaredFields();
那么ResultSet的各列名与目标实体类属性我们都已经获取到了,接下来让他们两辆配对,两两配对我们必定要用到循环嵌套:
for (Field field : t_fields) {
fieldName = field.getName();
Method method;
for (String columnName : columnNames) {
if (columnName.toLowerCase().equals(
fieldName.toLowerCase())) {
if (rs.getObject(columnName) != null) {
String setMethodName = getMethodName(fieldName);
method = t.getClass().getDeclaredMethod(
setMethodName, field.getType());
method.invoke(
t,
convertDataType(field.getType(), rs
.getObject(field.getName())
.toString()));
}
columnNames.remove(columnName);
break;
}
}
if (columnNames.size() == 0) {
break;
}
}
比较的时候注意大小写同步,如果已经匹配成功,我们则要将ResultSet行中对应列名的值赋值给实体类t,此时我们需要能访问t的setter方法来赋值,已知属性名查询对应set方法名:
/**
* 查询方法名
*
* @param fieldName
* @return
*/
private String getMethodName(String fieldName) {
String methodName = "set" + fieldName.substring(0, 1).toUpperCase()
+ fieldName.substring(1);
return methodName;
}
方法名知道了我们还需要去获取到这个方法:
Method method = t.getClass().getDeclaredMethod(setMethodName, field.getType());
Method我们已经获取成功了,接下来就是最后一部通过set方法给实体类赋值了:
method.invoke(t,convertDataType(field.getType(), rs.getObject(field.getName()).toString()));
至此我们通过反射来给实体类赋值就结束了。
有兴趣的可以去查询下反射类的API,主要从以下几个类获取方法:
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;