1、什么是反射?
反射是Java的特征之一,是一种间接操作目标对象的机制,核心是JVM在运行的时候才动态加载类,并且对于任意一个类,都能够知道这个类的所有属性和方法,调用方法/访问属性,不需要提前在编译期知道运行的对象是谁,允许运行中的Java程序获取类的信息,并且可以操作类或对象内部属性。
2、反射机制的主要作用?
通过反射机制访问Java对象的属性和方法。
3、反射应用场景?
(1)JDBC驱动加载;
(2)MyBatis框架;
(3)Spring IOC框架等。
4、反射机制获取类的几种方法?
(1)Class.forName("类的全路径") 例如:cn.liuyh8.reflection.User;
(2)User.class;
(3)(new User).getClass。
5、以封装JDBC为例,来说明反射机制的使用方式
(1)JDBC获取数据库连接驱动----单例模式
public class DButil {
private static String driver = "";
private static String url = "";
private static String username= "";
private static String password = "";
//使用hutool工具包
private static Props props;
/**
* 静态代码块,在类加载进内存时就完成对对象的特殊的初始化
* 这个动作发生在类的构造器执行之前,也就是在没有对象存在的情况下,静态代码就已经完成了对对象的特殊的处理
* 此处作用是读取配置文件中的配置信息,并准备数据库驱动
*/
static {
props = new Props("config/config.properties");
driver = props.getProperty("jdbc.driver");
url = props.getProperty("jdbc.url");
username = props.getProperty("jdbc.username");
password = props.getProperty("jdbc.password");
try {
Class.forName(driver);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private DButil() {}
/**
* 单例模式
*/
private static DButil instance = null;
public static DButil getInstance() {
if(instance == null){
synchronized(DbUtil.class){
if(instance == null){
instance = new DButil();
}
}
}
return instance;
}
/**
* 创建数据库连接
* @return
* @throws SQLException
*/
public Connection getConnection() throws SQLException {
return DriverManager.getConnection(url, username, password);
}
public void closeConnection(Connection conn) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
(2)实例化对象,实现JDBC列表的封装查询
/**
* 获取列表
*
* @param id sql对应的id值,此id全局唯一,类似于mybatis中select标签中的id值
* @param map 参数列表
* @param clazz
* @return
* @throws Exception
*/
public List<Object> findList(String id, Map<String, String> map, Class<?> clazz) throws Exception {
/* 执行sql */
ResultSet rs = this.get(id,map).executeQuery();
List<Object> list = new ArrayList<>();
Object obj = null;
while (rs.next()) {
/* 实例化一个对象,调用了无参构造方法 */
obj = clazz.getDeclaredConstructor().newInstance();
//实例化一个有参构造方法clazz.getDeclaredConstructor(String.class,String.class).newInstance("123","abc");
list.add(this.getObject(obj, rs));
}
return list;
}
private Object getObject(Object obj, ResultSet rs) throws Exception {
ResultSetMetaData rsmeta = rs.getMetaData();
/* 获取结果集中的字段数 */
int count = rsmeta.getColumnCount();
/* 循环取出个字段的名字以及他们的值并将其作为值赋给对应的实体对象的属性 */
for (int i = 0; i < count; i++) {
// 获取字段名
String name = (rsmeta.getColumnName(i + 1));
// 利用反射将结果集中的字段名与实体对象中的属性名相对应
// 由于对象的属性都是私有的所以要想访问必须加上getDeclaredField(name)和
if (!"rownumber".equals(name)) {
//UnderlineToHump为将数据库字段转为驼峰命名法,此处需要注意的是实体类的属性名称必须和数据库驼峰命名法后的相同,或者别名相同
//Field []field = obj.getClass().getDeclaredFields();
//根据驼峰明明转换后的字段名,来获取字段信息
Field f = obj.getClass().getDeclaredField(UnderlineToHump(name));
//允许反射赋值
f.setAccessible(true);
// 将结果集中的值赋给相应的对象实体的属性
f.set(obj, rs.getObject(name));
}
}
return obj;
}
(3)使用方法(分页查询用户列表)
public PageUtils<SysUser> list(Integer pageNum,String name) throws Exception {
Integer pageSize = 10;
String data = "";
Map<String,String> map = new HashMap<>();
map.put("1","int," +((pageNum-1) * pageSize)+"");
map.put("2","int," + pageSize);
int totalRecord = dao.count();
PageUtils<SysUser> p = new PageUtils<>(pageNum,pageSize,totalRecord,"user/list",data);
p.setList((List<SysUser>)(List)dao.findList("userList",map,SysUser.class));
return p;
}