俗话说得好:“反射反射,程序员的快乐” 。用好反射,可以使你的开发效率事半功倍。反射技术作为Java特性,已经成为框架构建的基础。如果灵活掌握反射,可谓“一步登天”!
JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
Java的反射机制是在编译并不确定是哪个类被加载了,而是在程序运行的时候才加载、操作。使用在编译期并不知道的类,这样的特点就是反射。
我们在做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瞬间搞定。
不说了,我去喝可乐了!下次老王继续和你分享Java World!
原文:https://www.cnblogs.com/laownag/p/10770890.html