前言
俗话说得好:“反射反射,程序员的快乐” 。用好反射,可以使你的开发效率事半功倍。反射技术作为Java特性,已经成为框架构建的基础。如果灵活掌握反射,可谓“一步登天”!
什么是反射?
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、操作。使用在编译期并不知道的类,这样的特点就是反射。
反射的作用?
- 由于众多框架都是用到了反射机制(例如Spring的IOC与AOP,Hibernate的对象实体关系映射),学了反射我们可以更好的学习框架;
- 根据反射的特点,我们可以通过反射来了解类的构成,做出一系列比较通用的工具代码(也就是框架);
- 将许多代码变为自动化实现,以此达到减少开发周期的目的。
- 节约下来的时间可以和美女愉快的交流,或者躲在角落处快乐的喝肥宅水^_^(这条比较关键!)
Case1:
我们在做JDBC查询数据库时,希望把数据库中的多条记录保存到java中的一个List中对象,例如将Scott的EMP(oracle示例表,oracle安装后自带)表的数据放到java中的Emp的对象中,然后再将Emp的对象放到一个集合中:
package cn.gzsxt.test;
import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.List;
import cn.gzsxt.model.Emp;import cn.gzsxt.util.DBUtil;
public class TestEmp {
public List getAllEmp() {
List list = new ArrayList<>();
Connection conn = DBUtil.getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
try {
String sql = "select * from emp";
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
while (rs.next()) {
// 创建一个Emp的对象
Emp e = new Emp();
e.setEmpno(rs.getInt("empno"));
e.setEname(rs.getString("ename"));
e.setJob(rs.getString("job"));
e.setMgr(rs.getInt("mgr"));
e.setHiredate(rs.getDate("hiredate"));
e.setSal(rs.getDouble("sal"));
e.setComm(rs.getDouble("comm"));
e.setDeptno(rs.getInt("deptno"));
list.add(e);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
DBUtil.close(conn, ps, rs);
}
return list;
}
}
写过JDBC的同学都清楚,红色部分代码的意义是创建对象,并为对象的属性赋值。这些操作其实是“没有意义的体力活”。如果下次查询Dept表,还要创建Dept对象,所以我们可以利用反射将其封装成一个方法:
package cn.gzsxt.test;
import java.lang.reflect.Field;import java.lang.reflect.Method;import java.sql.Connection;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.ResultSetMetaData;
import java.util.ArrayList;import java.util.List;import cn.gzsxt.util.DBUtil;
public class TestEmp {
// 目的:将数据库中的一行记录转化为java中一个对象
public List rows2beans(String sql, Class cls) {
List list = new ArrayList();
Connection conn = DBUtil.getConnection();
PreparedStatement ps = null;
ResultSet rs = null;
try {
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
// 每一个rs对象都对应一个ResultSetMetaData对象
ResultSetMetaData rsmd = rs.getMetaData();
// 获取查询的列数
int count = rsmd.getColumnCount();
while (rs.next()) {
Object object = cls.newInstance(); //cls决定生成什么对象
for (int i = 0; i < count; i++) {
// 获取第一列的名字
String fieldName = rsmd.getColumnName(i + 1).toLowerCase();
// 通过列名获取类中的属性的表述对象
Field field = cls.getDeclaredField(fieldName);
// 根据set方法名获取set方法对应的表述对象
Method m = cls.getDeclaredMethod(getSetMethodName(fieldName), field.getType());
Object objval = rs.getObject(fieldName);
if (objval != null) {
if (objval instanceof Number) {
if (field.getType().getName().equals("int")) {
m.invoke(object, rs.getInt(fieldName));
} else if (field.getType().getName().equals("long")) {
m.invoke(object, rs.getLong(fieldName));
} else if (field.getType().getName().equals("double")) {
m.invoke(object, rs.getDouble(fieldName));
} else if (field.getType().getName().equals("short")) {
m.invoke(object, rs.getShort(fieldName));
} else if (field.getType().getName().equals("byte")) {
m.invoke(object, rs.getByte(fieldName));
} else if (field.getType().getName().equals("float")) {
m.invoke(object, rs.getFloat(fieldName));
}
} else {
m.invoke(object, objval);
}
}
}
list.add(object);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
DBUtil.close(conn, ps, rs);
}
return list;
}
// 根据属性名获取该属性的set方法的名字
public String getSetMethodName(String fieldName) {
return "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
}
至此,我们就完成了对任意一条SQL语句的查询封装,尽管这个方法还有很多不如意的地方,比如:sql没有参数。但不管怎么说这个方法使用起来就很方便了,我们只需要给定sql语句以及要生成的类型即可得到一个有关一张表数据的List,一起来看main方法:
public static void main(String[] args) {
List list = obj.rows2beans("select * from emp", Emp.class);
System.out.println(list.size()) //数据为14条
}
好啦,今天的分享就到这里了!
这个封装的方法大家可以保存起来,
以后懒得写查询数据库的代码时,
ctrl+c和ctrl+v瞬间搞定。
不说了,我去喝可乐了!
原文地址:https://www.cnblogs.com/hehy0205/p/10773491.html