Java反射
反射的概念之类的就不写,今天写一下反射的用法以及实例:
package com.zs.entity; import java.util.Date; public class Emp { public int empno; public String ename; private String job; private int mgr; private Date hireDate; private double sal; private double comm; private int deptno; public Emp() { } private Emp(int empno, String ename, double sal) { this.empno = empno; this.ename = ename; this.sal = sal; } public int getEmpno() { return empno; } public void setEmpno(int empno) { this.empno = empno; } public String getEname() { return ename; } public void setEname(String ename) { this.ename = ename; } public String getJob() { return job; } public void setJob(String job) { this.job = job; } public int getMgr() { return mgr; } public void setMgr(int mgr) { this.mgr = mgr; } public Date getHireDate() { return hireDate; } public void setHireDate(Date hireDate) { this.hireDate = hireDate; } public double getSal() { return sal; } public void setSal(double sal) { this.sal = sal; } public double getComm() { return comm; } public void setComm(double comm) { this.comm = comm; } public int getDeptno() { return deptno; } public void setDeptno(int deptno) { this.deptno = deptno; } @Override public String toString() { return "Emp{" + "empno=" + empno + ", ename='" + ename + '\'' + ", job='" + job + '\'' + ", mgr=" + mgr + ", hireDate=" + hireDate + ", sal=" + sal + ", comm=" + comm + ", deptno=" + deptno + '}'; } }
上面创建实体类,我们通过这个实体类来理解反射
package com.zs.TestDemo; import com.zs.entity.Emp; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; /** * 创建反射对象的三种方式 * 1.类对象.getClass() * 2.类名.class * 3.Class.forName(); * 三种方式常用的是第三种 */ public class TestDemo { public static void main(String[] args) throws Exception { /* 1.getClass(),通过下面的代码可以看出,要想使用getClass()方法获得反射对象, 我们需要先创建一个类的实例化对象,可是我们获得反射就是为了获取实例化对象,已经有了实例化对象, 就不需要使用反射了,因此这种方法不常用*/ Emp emp = new Emp(); Class<? extends Emp> aClass = emp.getClass(); /*2.类名.class ,这种方式返回的反射对象类型,固定是Emp类型的*/ Class<Emp> clazz = Emp.class; /*3.Class.forName(),这种方式已经比较熟悉了, 在jdbc阶段,加载驱动就是用的这种方法*/ Class<?> aClass1 = Class.forName("com.zs.entity.Emp"); /** * 下面查看反射对象所具有的方法 */ /*1.getDeclaredFields(),获取该类所有的字段属性,包括私有的, * getDeclaredField("*"),获取名字为*的属性*/ Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { System.out.println(field); } Field ename = clazz.getDeclaredField("ename"); System.out.println(ename);//public java.lang.String com.zs.entity.Emp.ename /*2.上面是加 Declare 的方法,加了Declare就可以获取私有的属性了。不加只能获得修饰符为public的字段属性*/ Field[] fields1 = clazz.getFields(); for (Field field : fields1) { System.out.println(field); } Field empno = clazz.getField("empno"); /*3.与字段相对应, 方法也有这两种方式,添加Declare可以获取包括私有的方法,不加只能获取修饰符为public的方法*/ Method[] declaredMethods = clazz.getDeclaredMethods(); for (Method declaredMethod : declaredMethods) { System.out.println(declaredMethod); } /*获取方法名为**的方法*/ Method getEmpno = clazz.getDeclaredMethod("getEmpno"); Method[] methods = clazz.getMethods(); for (Method method : methods) { System.out.println(method); } Method getEmpno1 = clazz.getMethod("getEmpno"); /*4.使用反射对象,创建实例化对象*/ Emp emp1 = clazz.newInstance(); /*使用空参的构造方法*/ Constructor<Emp> constructor = clazz.getConstructor(); System.out.println(constructor + "11111111111"); /*有参构造方法,因为有参构造为私有的方法,因此要用有Declare的方法*/ Constructor<Emp> constructor1 = clazz.getDeclaredConstructor(int.class, String.class, double.class); System.out.println(constructor1); /*与字段一样,构造方法也有Declare的区分,加了Declare后就可以获取私有的构造方法*/ Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor); } /*5.在这些反射对象的属性中,还有其他的方法*/ Field[] declaredFields = clazz.getDeclaredFields(); for (Field declaredField : declaredFields) { /*字段的名字以及类型,这两个方法同样可以用在方法上,就不演示了*/ System.out.println(declaredField.getName() + "11" + declaredField.getType()); } /*具体的方法还有很多,有兴趣可以自己去测试*/ } }
反射的具体使用,在之前的jdbc工具类中,我们只能将数据封装入list<map>集合中,因为工具类搜索的表是可变的,因为我们没有办法将对象传递过去,在工具类中,创建不同的对象,所以没有办法在工具类中返回对象的集合,在学习了反射后,就可以将搜索结果存入对象了。
//查询方法 public <T> List<T> queryToBean(String sql, Class<?> clazz, Object... args) { //创建返回list集合 List<T> list=new ArrayList<>(); try { //获取结果集 rs=pretreatmentSql(sql, args).executeQuery(); //获取反射类的成员变量 Field[] fs = clazz.getDeclaredFields(); //遍历结果集每一行 while (rs.next()) { //创建反射类对象 T t = (T)clazz.newInstance(); //遍历成员变量 for (Field f : fs) { //根据成员变量名获取反射类对象的 成员变量对象 Field field = t.getClass().getDeclaredField(f.getName()); //设置跨越访问权限进行操作 field.setAccessible(true); Object object = rs.getObject(f.getName()); //给成员变量对象赋值 field.set(t, object); } list.add(t); } } catch (Exception e) { e.printStackTrace(); }finally { try { close(); } catch (SQLException e) { e.printStackTrace(); } } return list; }
通过以上的方法,在调用方法时,传递要封装对象的class对象,就可以将搜索结果封装为对象了,需要注意的是,这种方法存在一定缺陷就是当数据库连表查询时,需要将你想要的数据字段都在要封装的对象中创建字段,因为是通过字段名到数据库的结果集中获取值的,因此就会造成一个实体类的字段与另一个实体类字段重复等问题。