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;

完整类代码链接:http://download.csdn.net/detail/wang124454731/9457303