JAVA反射機制
一、什么是反射機制
簡單的來說,反射機制指的是程序在運行時能夠獲取自身的信息。在java中,只要給定類的名字,
那么就可以通過反射機制來獲得類的所有信息。
二、哪里用到反射機制
添加一句:所有類的對象其實都是Class的實例。
有些時候,我們用過一些知識,但是並不知道它的專業術語是什么,在剛剛學jdbc時用過一行代碼,
Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那時候只知道那行代碼是生成
驅動對象實例,並不知道它的具體含義。聽了反射機制這節課后,才知道,原來這就是反射,現在很多開
框架都用到反射機制,hibernate、struts都是用反射機制實現的。
Java反射機制主要提供了以下功能:
在運行時判斷任意一個對象所屬的類;
在運行時構造任意一個類的對象;
在運行時判斷任意一個類所具有的成員變量和方法;
在運行時調用任意一個對象的方法;生成動態代理。
三、反射機制的優點與缺點
為什么要用反射機制?直接創建對象不就可以了嗎,這就涉及到了動態與靜態的概念,
靜態編譯:在編譯時確定類型,綁定對象,即通過。
動態編譯:運行時確定類型,綁定對象。動態編譯最大限度發揮了java的靈活性,體現了多
態的應用,有以降低類之間的藕合性。
一句話,反射機制的優點就是可以實現動態創建對象和編譯,體現出很大的靈活性,特別是在J2EE的開發中
它的靈活性就表現的十分明顯。比如,一個大型的軟件,不可能一次就把把它設計的很完美,當這個程序編
譯后,發布了,當發現需要更新某些功能時,我們不可能要用戶把以前的卸載,再重新安裝新的版本,假如
這樣的話,這個軟件肯定是沒有多少人用的。采用靜態的話,需要把整個程序重新編譯一次才可以實現功能
的更新,而采用反射機制的話,它就可以不用卸載,只需要在運行時才動態的創建和編譯,就可以實現該功
能。
它的缺點是對性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么並且它
滿足我們的要求。這類操作總是慢於只直接執行相同的操作。
四、利用反射機制能獲得什么信息
一句話,類中有什么信息,它就可以獲得什么信息,不過前提是得知道類的名字,要不就沒有后文了
首先得根據傳入的類的全名來創建Class對象。
Class c=Class.forName("className");注明:className必須為全名,也就是得包含包名,比如,cn.netjava.pojo.UserInfo;
Object obj=c.newInstance();//創建對象的實例
OK,有了對象就什么都好辦了,想要什么信息就有什么信息了。
獲得構造函數的方法
Constructor getConstructor(Class[] params)//根據指定參數獲得public構造器
Constructor[] getConstructors()//獲得public的所有構造器
Constructor getDeclaredConstructor(Class[] params)//根據指定參數獲得public和非public的構造器
Constructor[] getDeclaredConstructors()//獲得public的所有構造器
獲得類方法的方法
Method getMethod(String name, Class[] params),根據方法名,參數類型獲得方法
Method[] getMethods()//獲得所有的public方法,包含繼承的
Method getDeclaredMethod(String name, Class[] params)//根據方法名和參數類型,獲得public和非public的方法
Method[] getDeclaredMethods()//獲得所以的public和非public方法 ,不包含繼承的
獲得類中屬性的方法
Field getField(String name)//根據變量名得到相應的public變量
Field[] getFields()//獲得類中所以public的方法,
Field getDeclaredField(String name)//根據方法名獲得public和非public變量
Field[] getDeclaredFields()//獲得類中所有的public和非public方法 ,
常用的就這些,知道這些,其他的都好辦……
五、用反射機制能干什么事
剛開始在使用jdbc時侯,在編寫訪問數據庫時寫到想吐,有八個表,每個表都有增刪改查中操作
那時候還不知道有反射機制這個概念,所以就對不同的表創建不同的dao類,這樣不僅開發速率地,而且代碼
冗余的厲害,最要命的是看着差不多的,然后直接復制修改,由於容易犯各種低級的錯誤(大小寫啊,多一
個或少一個字母啊……),一個錯誤就可以讓你找半天。
有了java反射機制,什么都好辦了,只需要寫一個dao類,四個方法,增刪改查,傳入不同的對象,就OK啦,
無需為每一個表都創建dao類,反射機制會自動幫我們完成剩下的事情,這就是它的好處。說白了,反射機制就是專門
幫我們做那些重復的有規則的事情,所以現在很多的自動生成代碼的軟件就是運用反射機制來完成的,只要你按照規則
輸入相關的參數,所以低級的程序員慢慢的就被抹殺了,為什么?因為代碼都不用寫了,隨便一個人都會開發,還要程
序員干什么啊?所以我們只有一條出路,那就是努力努力再努力,成為高級程序員,專門開發傻瓜軟件,讓其他程序員 到 一邊涼快去,呵呵~
六、用反射機制實現對數據庫數據的增、查例子
基本原理;保存數據時,把需要保存的對象的屬性值全部取出來再拼湊sql語句
查詢時,將查詢到的數據全部包裝成一個java對象。
游戲規則:俗話說的好,無規矩不成方圓,特別是程序來說,它只能做有規則的事情,沒有規則的它干不了,好,那就
先定規則
1)數據庫的每一個表對象一個pojo類,表中的每一個字段對應pojo類的中的一個屬性。
並且pojo類的名字和表的名字相同,屬性名和字段名相同,大小寫沒有關系,因為數據庫一般不區分大小寫
2)為pojo類中的每一個屬性添加標准的set和get方法。
有了游戲規則,那么開始游戲吧。
1、首先數據庫的有一個表,假設數據庫名稱為:blogsystem,里面的一個表名userinfo。如圖:
2、創建對應的pojo類:
package cn.netjava.pojo;
public
class
UserInfo {
private
int
id
;
private String name;
private String pwd;
private
int
age;
@Override
public String toString() {
return
"UserInfo [id="
+
id
+
", name="
+
name
+
", pwd="
+
pwd
+
", age="
+
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 String getPwd() {
return
pwd;
}
public void setPwd(String pwd) {
this.pwd
=
pwd;
}
public
int
getAge() {
return
age;
}
public void setAge(
int
age) {
this.age
=
age;
}
}
package cn.netjava.factory;
import
java.sql.Connection;
import
java.sql.DriverManager;
public
class
Connect2DBFactory {
public static Connection getDBConnection() {
Connection conn
=
null;
try
{
Class.forName(
"com.mysql.jdbc.Driver"
);
String url
=
"jdbc:mysql://localhost:3306/blogsystem"
;
String user
=
"root"
;
String password
=
"netjava"
;
conn
=
DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
}
return
conn;
}
}
3、好戲開始啦,編寫操作數據庫的dao類
package cn.netjava.session;
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.SQLException;
import
java.sql.Statement;
import
java.util.ArrayList;
import
java.util.
List
;
import
cn.netjava.factory.Connect2DBFactory;
import
cn.netjava.pojo.UserInfo;
public
class
NetJavaSession {
/
*
*
*
解析出保存對象的sql語句
*
@param
object
:需要保存的對象
*
@
return
:保存對象的sql語句
*
/
public static String getSaveObjectSql(
Object
object
) {
/
/
定義一個sql字符串
String sql
=
"insert into "
;
/
/
得到對象的類
Class c
=
object
.getClass();
/
/
得到對象中所有的方法
Method[] methods
=
c.getMethods();
/
/
得到對象中所有的屬性
Field[] fields
=
c.getFields();
/
/
得到對象類的名字
String cName
=
c.getName();
/
/
從類的名字中解析出表名
String tableName
=
cName.substring(cName.lastIndexOf(
"."
)
+
1
,
cName.length());
sql
+
=
tableName
+
"("
;
List
<String> mList
=
new ArrayList<String>();
List
vList
=
new ArrayList();
for
(Method method : methods) {
String mName
=
method.getName();
if
(mName.startsWith(
"get"
) && !mName.startsWith(
"getClass"
)) {
String fieldName
=
mName.substring(
3
, mName.length());
mList.add(fieldName);
System.out.println(
"字段名字----->"
+
fieldName);
try
{
Object
value
=
method.invoke(
object
, null);
System.out.println(
"執行方法返回的值:"
+
value);
if
(value instanceof String) {
vList.add(
"\""
+
value
+
"\""
);
System.out.println(
"字段值------>"
+
value);
}
else
{
vList.add(value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
for
(
int
i
=
0
; i < mList.size(); i
+
+
) {
if
(i < mList.size()
-
1
) {
sql
+
=
mList.get(i)
+
","
;
}
else
{
sql
+
=
mList.get(i)
+
") values("
;
}
}
for
(
int
i
=
0
; i < vList.size(); i
+
+
) {
if
(i < vList.size()
-
1
) {
sql
+
=
vList.get(i)
+
","
;
}
else
{
sql
+
=
vList.get(i)
+
")"
;
}
}
return
sql;
}
public static
List
getDatasFromDB(String tableName,
int
Id
) {
return
null;
}
/
*
*
*
將對象保存到數據庫中
*
@param
object
:需要保存的對象
*
@
return
:方法執行的結果;
1
:表示成功,
0
:表示失敗
*
/
public
int
saveObject(
Object
object
) {
Connection con
=
Connect2DBFactory.getDBConnection();
String sql
=
getSaveObjectSql(
object
);
try
{
/
/
Statement statement
=
(Statement) con.createStatement();
PreparedStatement psmt
=
con.prepareStatement(sql);
psmt.executeUpdate();
return
1
;
} catch (SQLException e) {
e.printStackTrace();
return
0
;
}
}
/
*
*
*
從數據庫中取得對象
*
@param arg0
:對象所屬的類
*
@param
id
:對象的
id
*
@
return
:需要查找的對象
*
/
public
Object
getObject(String className,
int
Id
) {
/
/
得到表名字
String tableName
=
className.substring(className.lastIndexOf(
"."
)
+
1
,
className.length());
/
/
根據類名來創建Class對象
Class c
=
null;
try
{
c
=
Class.forName(className);
} catch (ClassNotFoundException e1) {
e1.printStackTrace();
}
/
/
拼湊查詢sql語句
String sql
=
"select * from "
+
tableName
+
" where Id="
+
Id
;
System.out.println(
"查找sql語句:"
+
sql);
/
/
獲得數據庫鏈接
Connection con
=
Connect2DBFactory.getDBConnection();
/
/
創建類的實例
Object
obj
=
null;
try
{
Statement stm
=
con.createStatement();
/
/
得到執行查尋語句返回的結果集
ResultSet
set
=
stm.executeQuery(sql);
/
/
得到對象的方法數組
Method[] methods
=
c.getMethods();
/
/
遍歷結果集
while
(
set
.
next
()) {
obj
=
c.newInstance();
/
/
遍歷對象的方法
for
(Method method : methods) {
String methodName
=
method.getName();
/
/
如果對象的方法以
set
開頭
if
(methodName.startsWith(
"set"
)) {
/
/
根據方法名字得到數據表格中字段的名字
String columnName
=
methodName.substring(
3
,
methodName.length());
/
/
得到方法的參數類型
Class[] parmts
=
method.getParameterTypes();
if
(parmts[
0
]
=
=
String.
class
) {
/
/
如果參數為String類型,則從結果集中按照列名取得對應的值,並且執行改
set
方法
method.invoke(obj,
set
.getString(columnName));
}
if
(parmts[
0
]
=
=
int
.
class
) {
method.invoke(obj,
set
.getInt(columnName));
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return
obj;
}
}
4、開始測試效果怎么樣:
package cn.netjava.tester;
import
cn.netjava.pojo.UserInfo;
import
cn.netjava.session.NetJavaSession;
public
class
Tester {
public static void main(String args[]) {
/
/
獲得NetJavaSession對象
NetJavaSession session
=
new NetJavaSession();
/
/
創建一個UserInfo對象
UserInfo user
=
new UserInfo();
/
/
設置對象的屬性
user.setId(
6988
);
user.setAge(
44
);
user.setPwd(
"pwd"
);
user.setName(
"champion"
);
/
/
將對象保存到數據庫中
String sql
=
session.getSaveObjectSql(user);
System.out.println(
"保存對象的sql語句:"
+
sql);
/
/
查找對象
UserInfo userInfo
=
(UserInfo) session.getObject(
"cn.netjava.pojo.UserInfo"
,
6988
);
System.out.println(
"獲取到的信息:"
+
userInfo);
}
}
5、打印出來的結果:
七、總節一下
總的來說,java反射機制是一個很好用的東西,用它可以解決很多死的東西,因為反射機制的靈活行很大,有了他,我們就不要花太多的時間來寫操做數據庫的代碼了,而是方法更多的時間在項目的邏輯功能上,這個可以很大的減少開發時間,而且代碼的可讀性好。先在的很多開源框架都是才用的反射機制,它只要配置文件,然后按規則來調用他的方法就可以了。
轉載@①塊腹肌
https://www.cnblogs.com/jqyp/archive/2012/03/29/2423112.html