前言:
我们通过一个实际的例子来演示反射在编程中的应用,学一个技术,一定是要应用的,可能之前大家对反射的学习,仅仅是停留在概念层面,不知道反射究竟应用在哪,所以是一头雾水。相信通过这篇教程,会让你对反射有一个更深层次的认知。
首先简单介绍反射的概念:
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
如何理解反射?简单的一句话解释,将传统的开发思路反向逆转。
传统的方式是通过类创建对象:类 ---> 对象。 反射就是将这个过程逆转,通过对象得到类:对象 ---> 类。
通过对象得到的这个类该如何表示? 使用Class类来表示,此类是Java反射的源头,是用来描述其他类的类,Class类的每一个实例化对象就是对其他类的描述。
在Object类中定义了以下的方法,此方法将被所有子类继承: public final Class getClass()。 也就是说每一个类,都可以调用getClass()方法获取对应的Class对象,用来描述目标类,我们将这个Class类叫做目标类的运行时类。
有了Class对象,能做什么?
调用Class对象的newInstance()方法,可以动态创建目标类的对象。 要求: 1)目标类必须有无参数构造方法。 2)外部方法有足够的权限访问目标类的构造方法。
除了动态创建目标类的对象,反射也可以动态调用对象的各种方法,访问成员变量。
Java反射机制提供的功能
在运行时判断任意一个对象所属的类。 在运行时构造任意一个类的对象。 在运行时判断任意一个类所具有的成员变量和方法。 在运行时调用任意一个对象的成员变量和方法。
反射相关的主要API
java.lang.Class:描述一个类。 java.lang.reflect.Method:描述类的方法。 java.lang.reflect.Field:描述类的成员变量。 java.lang.reflect.Constructor:描述类的构造方法。
Class用来描述目标类的结构,叫做目标类的运行时类。 Class的常用方法: public Class?>[] getInterfaces() 返回运行时类实现的全部接口。
public Class super="" t=""?> getSuperclass() 返回运行时类的父类。
public Constructor[] getConstructors() 返回运行时类的public构造方法。
public Constructor[] getDeclaredConstructors() 返回运行时类的全部构造方法。
public Method[] getMethods() 返回运行时类的public方法。
public Method[] getDeclaredMethods() 返回运行时类的全部方法。
public Field[] getFields() 返回运行时类的public成员变量。
public Field[] getDeclaredFields() 返回运行时类的全部成员变量。
Method用来描述运行时类的方法。 Method的常用方法:
public Class?> getReturnType() 返回方法的返回值类型。
public Class?>[] getParameterTypes() 返回方法的参数列表。
public int getModifiers() 返回方法的访问权限修饰符。
public String getName(); 返回方法名。
public Class?>[] getExceptionTypes() 返回方法的异常信息。
Field用来描述运行时类的成员变量。 Field的常用方法: public int getModifiers() 返回成员变量的访问权限修饰符。
public Class?> getType() 返回成员变量的数据类型。
public String getName() 返回成员变量的名称。
Constructor用来描述运行时类的构造方法。 Constructor的常用方法: public int getModifiers() 返回构造方法的访问权限修饰符。
public String getName() 返回构造方法名。
public Class?>[] getParameterTypes() 返回构造方法参数列表。
反射在实际中的应用主要是动态创建对象,动态调用对象的方法。
1.创建对象: 调用Class类的newInstance()方法创建对象。
2.调用指定方法: (1)通过Class类的getMethod(String name,Class…parameterTypes)方法获取一个Method对象,并设置此方法操作时所需要的参数类型。 (2)调用Object invoke(Object obj, Object[] args)方法,并向方法中传递目标obj对象的参数信息。
代码:
需求: 创建一个查询数据库的工具类,自动将SQL语句查询出的结果集,封装成不同的对象返回,一个简化版的MyBatis工具。
思路: 工具类查询方法的参数列表:Connection对象,SQL语句,目标运行时类对象clazz,数据表的id值。
1.通过Connection对象,SQL语句,id值查询出对应的结果集。 2.利用反射机制调用clazz的无参构造方法创建目标对象。
3.获取clazz的Filed,即目标类的所有成员变量。 4.找到与成员变量名相同的结果集字段,并获取字段值。 5.通过成员变量名找到对应的setter方法。 6.利用反射机制调用setter方法完成赋值。
实现步骤: 1.导入mysql驱动,c3p0数据源相关jar包。 2.创建c3p0-config.xml。
c3p0-config>
named-config name='testc3p0'>
property name='user'>rootproperty> property name='password'>rootproperty> property name='driverClass'>com.mysql.jdbc.Driverproperty> property name='jdbcUrl'>jdbc:mysql://localhost:3306/school?useUnicode=true&characterEncoding=UTF-8property>
property name='acquireIncrement'>5property> property name='initialPoolSize'>5property> property name='minPoolSize'>5property> property name='maxPoolSize'>10property>
property name='maxStatements'>20property> property name='maxStatementsPerConnection'>5property>
named-config>
c3p0-config>
3.创建数据表student,user。
DROP TABLE IF EXISTS `student`; CREATE TABLE `student` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(11) DEFAULT NULL, `address` varchar(11) DEFAULT NULL, `tel` varchar(255) DEFAULT NULL, `score` double(11,1) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `age` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
4.创建实体类Student,User。
package com.southwind.entity;
public class Student { private int id; private String name; private String address; private String tel; private double score; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public double getScore() { return score; } public void setScore(double score) { this.score = score; } @Override public String toString() { return 'Student [id=' + id + ', name=' + name + ', address=' + address + ', tel=' + tel + ', score=' + score + ']'; }
}
package com.southwind.entity;
public class User { private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return 'User [id=' + id + ', name=' + name + ', age=' + age + ']'; }
}
5.创建JDBCTools工具类。
package com.southwind.util;
import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement;
import com.mchange.v2.c3p0.ComboPooledDataSource;
public class JDBCTools { private static ComboPooledDataSource dataSource;
static{ dataSource = new ComboPooledDataSource('testc3p0'); }
/** * 获取Connection * @return */ public static Connection getConnection(){ try { return dataSource.getConnection(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; }
/** * 释放资源 * @param conn * @param stmt * @param rs */ public static void release(Connection conn,Statement stmt,ResultSet rs){ if(conn != null){ try { conn.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(stmt != null){ try { stmt.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } if(rs != null){ try { rs.close(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
6.创建数据库查询工具类MyQueryRunner,核心代码。
package com.southwind.util;
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.sql.SQLException;
/** * 通用工具类 * @author southwind * */ public class MyQueryRunner {
/** * 将结果集动态封装成对象 * @param conn * @param sql * @param clazz * @param id * @return */ public Object query(Connection conn,String sql,Class clazz,int id){ PreparedStatement pstmt = null; ResultSet rs = null; Object obj = null; try { pstmt = conn.prepareStatement(sql); pstmt.setInt(1, id); rs = pstmt.executeQuery(); obj = clazz.newInstance(); if(rs.next()){ //遍历实体类属性集合,依次将结果集中的值赋给属性 Field[] fields = clazz.getDeclaredFields(); //获取ResultSet数据 ResultSetMetaData rsmd = rs.getMetaData(); for(int i = 0; i < fields.length;=""> Object value = setFieldValueByResultSet(fields[i],rsmd,rs); //通过属性名找到对应的setter方法 String name = fields[i].getName(); name = name.substring(0, 1).toUpperCase() + name.substring(1); String MethodName = 'set'+name; Method methodObj = clazz.getMethod(MethodName,fields[i].getType()); //调用setter方法完成赋值 methodObj.invoke(obj, value); } } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } return obj; }
/** * 根据将结果集中的值赋给对应的属性 * @param field * @param rsmd * @param rs * @return */ public Object setFieldValueByResultSet(Field field,ResultSetMetaData rsmd,ResultSet rs){ Object result = null; try { int count = rsmd.getColumnCount(); for(int i=1;i<> //找到与属性名相同的结果集字段 if(field.getName().equals(rsmd.getColumnName(i))){ //获取属性的数据类型 String type = field.getType().getName(); switch (type) { case 'int': result = rs.getInt(field.getName()); break; case 'java.lang.String': result = rs.getString(field.getName()); break; case 'double': result = rs.getDouble(field.getName()); break; } } } } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; } }
7.测试 通过id查询student表,调用工具方法,直接返回Student对象。
package com.southwind.test;
import java.sql.Connection; import com.southwind.entity.Student; import com.southwind.util.MyQueryRunner; import com.southwind.util.JDBCTools;
public class Test { public static void main(String[] args) { Connection conn = JDBCTools.getConnection(); String sql = 'select * from student where id = ?'; MyQueryRunner myQueryRunner = new MyQueryRunner(); Student student = (Student) myQueryRunner.query(conn, sql, Student.class, 1); System.out.println(student); } }
![](http://image109.360doc.com/DownloadImg/2018/04/2116/130835522_1_20180421040836175)
通过id查询user表,调用工具方法,直接返回User对象。
package com.southwind.test;
import java.sql.Connection; import com.southwind.entity.User; import com.southwind.util.MyQueryRunner; import com.southwind.util.JDBCTools;
public class Test { public static void main(String[] args) { Connection conn = JDBCTools.getConnection(); String sql = 'select * from users where id = ?'; MyQueryRunner myQueryRunner = new MyQueryRunner(); User user = (User) myQueryRunner.query(conn, sql, User.class, 30); System.out.println(user); } }
![](http://image109.360doc.com/DownloadImg/2018/04/2116/130835522_2_20180421040836269)
源码:
github https://github.com/southwind9801/ReflectDemo.git
![](http://image109.360doc.com/DownloadImg/2018/04/2116/130835522_3_20180421040836347)
![](http://image109.360doc.com/DownloadImg/2018/04/2116/130835522_4_20180421040836378)
【框架合集】SpringMVC教程汇总
【框架合集】Hibernate教程汇总
【框架合集】MyBatis教程汇总
【框架合集】Spring教程汇总
扫描下方二维码,加入Java大联盟
|