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;
}