Java反射機(jī)制的學(xué)習(xí)總結(jié)
一、什么是反射機(jī)制
簡單的來說,反射機(jī)制指的是程序在運(yùn)行時(shí)能夠獲取自身的信息。在java中,只要給定類的名字,那么就可以通過反射機(jī)制來獲得類的所有信息。
二、哪里用到反射機(jī)制
有些時(shí)候,我們用過一些知識(shí),但是并不知道它的專業(yè)術(shù)語是什么,在剛剛學(xué)jdbc時(shí)用過一行代碼, Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那時(shí)候只知道那行代碼是生成驅(qū)動(dòng)對(duì)象實(shí)例,并不知道它的具體含義。聽了反射機(jī)制這節(jié)課后,才知道,原來這就是反射,現(xiàn)在很多開框架都用到反射機(jī)制,hibernate、struts都是用反射機(jī)制實(shí)現(xiàn)的。
三、反射機(jī)制的優(yōu)點(diǎn)與缺點(diǎn)
為什么要用反射機(jī)制?直接創(chuàng)建對(duì)象不就可以了嗎,這就涉及到了動(dòng)態(tài)與靜態(tài)的概念,
靜態(tài)編譯:在編譯時(shí)確定類型,綁定對(duì)象,即通過。
動(dòng)態(tài)編譯:運(yùn)行時(shí)確定類型,綁定對(duì)象。動(dòng)態(tài)編譯最大限度發(fā)揮了java的靈活性,體現(xiàn)了多態(tài)的應(yīng)用,有以降低類之間的藕合性。
一句話,反射機(jī)制的優(yōu)點(diǎn)就是可以實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建對(duì)象和編譯,體現(xiàn)出很大的靈活性,特別是在J2EE的開發(fā)中它的靈活性就表現(xiàn)的十分明顯。比如,一個(gè)大型的軟件,不可能一次就把把它設(shè)計(jì)的很完美,當(dāng)這個(gè)程序編譯后,發(fā)布了,當(dāng)發(fā)現(xiàn)需要更新某些功能時(shí),我們不可能要用戶把以前的卸載,再重新安裝新的版本,假如這樣的話,這個(gè)軟件肯定是沒有多少人用的。采用靜態(tài)的話,需要把整個(gè)程序重新編譯一次才可以實(shí)現(xiàn)功能的更新,而采用反射機(jī)制的話,它就可以不用卸載,只需要在運(yùn)行時(shí)才動(dòng)態(tài)的創(chuàng)建和編譯,就可以實(shí)現(xiàn)該功能。
它的缺點(diǎn)是對(duì)性能有影響。使用反射基本上是一種解釋操作,我們可以告訴JVM,我們希望做什么并且它滿足我們的要求。這類操作總是慢于只直接執(zhí)行相同的操作。
四、利用反射機(jī)制能獲得什么信息
一句話,類中有什么信息,它就可以獲得什么信息,不過前提是得知道類的名字,要不就沒有后文了首先得根據(jù)傳入的類的全名來創(chuàng)建Class對(duì)象。
Class c=Class.forName("className");注明:className必須為全名,也就是得包含包名,比如,cn.netjava.pojo.UserInfo;
Object obj=c.newInstance();//創(chuàng)建對(duì)象的實(shí)例
OK,有了對(duì)象就什么都好辦了,想要什么信息就有什么信息了。
獲得構(gòu)造函數(shù)的方法
Constructor getConstructor(Class[] params)//根據(jù)指定參數(shù)獲得public構(gòu)造器
Constructor[] getConstructors()//獲得public的所有構(gòu)造器
Constructor getDeclaredConstructor(Class[] params)//根據(jù)指定參數(shù)獲得public和非public的構(gòu)造器
Constructor[] getDeclaredConstructors()//獲得public的所有構(gòu)造器
獲得類方法的方法
Method getMethod(String name, Class[] params),根據(jù)方法名,參數(shù)類型獲得方法
Method[] getMethods()//獲得所有的public方法
Method getDeclaredMethod(String name, Class[] params)//根據(jù)方法名和參數(shù)類型,獲得public和非public的方法
Method[] getDeclaredMethods()//獲得所以的public和非public方法
獲得類中屬性的方法
Field getField(String name)//根據(jù)變量名得到相應(yīng)的public變量
Field[] getFields()//獲得類中所以public的方法
Field getDeclaredField(String name)//根據(jù)方法名獲得public和非public變量
Field[] getDeclaredFields()//獲得類中所有的public和非public方法
常用的就這些,知道這些,其他的都好辦……
五、用反射機(jī)制能干什么事
剛開始在使用jdbc時(shí)侯,在編寫訪問數(shù)據(jù)庫時(shí)寫到想吐,有八個(gè)表,每個(gè)表都有增刪改查中操作,那時(shí)候還不知道有反射機(jī)制這個(gè)概念,所以就對(duì)不同的表創(chuàng)建不同的dao類,這樣不僅開發(fā)速率地,而且代碼冗余的厲害,最要命的是看著差不多的,然后直接復(fù)制修改,由于容易犯各種低級(jí)的錯(cuò)誤(大小寫啊,多一個(gè)或少一個(gè)字母啊……),一個(gè)錯(cuò)誤就可以讓你找半天。
有了java反射機(jī)制,什么都好辦了,只需要寫一個(gè)dao類,四個(gè)方法,增刪改查,傳入不同的對(duì)象,就OK啦,無需為每一個(gè)表都創(chuàng)建dao類,反射機(jī)制會(huì)自動(dòng)幫我們完成剩下的事情,這就是它的好處。說白了,反射機(jī)制就是專門幫我們做那些重復(fù)的有規(guī)則的事情,所以現(xiàn)在很多的自動(dòng)生成代碼的軟件就是運(yùn)用反射機(jī)制來完成的,只要你按照規(guī)則輸入相關(guān)的參數(shù),所以低級(jí)的程序員慢慢的就被抹殺了,為什么?因?yàn)榇a都不用寫了,隨便一個(gè)人都會(huì)開發(fā),還要程序員干什么???所以我們只有一條出路,那就是努力努力再努力,成為高級(jí)程序員,專門開發(fā)傻瓜軟件,讓其他程序員 到 一邊涼快去,呵呵~
六、用反射機(jī)制實(shí)現(xiàn)對(duì)數(shù)據(jù)庫數(shù)據(jù)的增、查例子
基本原理;保存數(shù)據(jù)時(shí),把需要保存的對(duì)象的屬性值全部取出來再拼湊sql語句查詢時(shí),將查詢到的數(shù)據(jù)全部包裝成一個(gè)java對(duì)象。
游戲規(guī)則:俗話說的好,無規(guī)矩不成方圓,特別是程序來說,它只能做有規(guī)則的事情,沒有規(guī)則的它干不了,好,那就先定規(guī)則
1)數(shù)據(jù)庫的每一個(gè)表對(duì)象一個(gè)pojo類,表中的每一個(gè)字段對(duì)應(yīng)pojo類的中的一個(gè)屬性。并且pojo類的名字和表的名字相同,屬性名和字段名相同,大小寫沒有關(guān)系,因?yàn)閿?shù)據(jù)庫一般不區(qū)分大小寫
2)為pojo類中的每一個(gè)屬性添加標(biāo)準(zhǔn)的set和get方法。
有了游戲規(guī)則,那么開始游戲吧。
1、首先數(shù)據(jù)庫的有一個(gè)表,假設(shè)數(shù)據(jù)庫名稱為:blogsystem,里面的一個(gè)表名userinfo。如圖:
2、創(chuàng)建對(duì)應(yīng)的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;
}
}
2、編寫獲得數(shù)據(jù)庫連接的工廠類:
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、好戲開始啦,編寫操作數(shù)據(jù)庫的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 {
/**
* 解析出保存對(duì)象的sql語句
*
* @param object
* :需要保存的對(duì)象
* @return:保存對(duì)象的sql語句
*/
public static String getSaveObjectSql(Object object) {
// 定義一個(gè)sql字符串
String sql = "insert into ";
// 得到對(duì)象的類
Class c = object.getClass();
// 得到對(duì)象中所有的方法
Method[] methods = c.getMethods();
// 得到對(duì)象中所有的屬性
Field[] fields = c.getFields();
// 得到對(duì)象類的名字
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("執(zhí)行方法返回的值:" + 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;
}
/**
* 將對(duì)象保存到數(shù)據(jù)庫中
*
* @param object
* :需要保存的對(duì)象
* @return:方法執(zhí)行的結(jié)果;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;
}
}
/**
* 從數(shù)據(jù)庫中取得對(duì)象
*
* @param arg0
* :對(duì)象所屬的類
* @param id
* :對(duì)象的id
* @return:需要查找的對(duì)象
*/
public Object getObject(String className, int Id) {
// 得到表名字
String tableName = className.substring(className.lastIndexOf(".") + 1,
className.length());
// 根據(jù)類名來創(chuàng)建Class對(duì)象
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);
// 獲得數(shù)據(jù)庫鏈接
Connection con = Connect2DBFactory.getDBConnection();
// 創(chuàng)建類的實(shí)例
Object obj = null;
try {
Statement stm = con.createStatement();
// 得到執(zhí)行查尋語句返回的結(jié)果集
ResultSet set = stm.executeQuery(sql);
// 得到對(duì)象的方法數(shù)組
Method[] methods = c.getMethods();
// 遍歷結(jié)果集
while (set.next()) {
obj = c.newInstance();
// 遍歷對(duì)象的方法
for (Method method : methods) {
String methodName = method.getName();
// 如果對(duì)象的方法以set開頭
if (methodName.startsWith("set")) {
// 根據(jù)方法名字得到數(shù)據(jù)表格中字段的名字
String columnName = methodName.substring(3,
methodName.length());
// 得到方法的參數(shù)類型
Class[] parmts = method.getParameterTypes();
if (parmts[0] == String.class) {
// 如果參數(shù)為String類型,則從結(jié)果集中按照列名取得對(duì)應(yīng)的值,并且執(zhí)行改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、開始測(cè)試效果怎么樣:
package cn.netjava.tester;
import cn.netjava.pojo.UserInfo;
import cn.netjava.session.NetJavaSession;
public class Tester {
public static void main(String args[]) {
//獲得NetJavaSession對(duì)象
NetJavaSession session = new NetJavaSession();
//創(chuàng)建一個(gè)UserInfo對(duì)象
UserInfo user = new UserInfo();
//設(shè)置對(duì)象的屬性
user.setId(6988);
user.setAge(44);
user.setPwd("pwd");
user.setName("champion");
//將對(duì)象保存到數(shù)據(jù)庫中
String sql = session.getSaveObjectSql(user);
System.out.println("保存對(duì)象的sql語句:" + sql);
//查找對(duì)象
UserInfo userInfo = (UserInfo) session.getObject(
"cn.netjava.pojo.UserInfo", 6988);
System.out.println("獲取到的信息:" + userInfo);
}
}
5、打印出來的結(jié)果:

七、總節(jié)一下
總的來說,java反射機(jī)制是一個(gè)很好用的東西,用它可以解決很多死的東西,因?yàn)榉瓷錂C(jī)制的靈活行很大,有了他,我們就不要花太多的時(shí)間來寫操做數(shù)據(jù)庫的代碼了,而是方法更多的時(shí)間在項(xiàng)目的邏輯功能上,這個(gè)可以很大的減少開發(fā)時(shí)間,而且代碼的可讀性好。先在的很多開源框架都是才用的反射機(jī)制,它只要配置文件,然后按規(guī)則來調(diào)用他的方法就可以了。
相關(guān)文章
SpringBoot自帶模板引擎Thymeleaf使用示例詳解
Thymeleaf是一款用于渲染XML/HTML5內(nèi)容的模板引擎,類似JSP,它可以輕易的與SpringMVC等Web框架進(jìn)行集成作為Web應(yīng)用的模板引擎,本文給大家介紹SpringBoot自帶模板引擎Thymeleaf使用示例,感興趣的朋友一起看看吧2023-12-12SpringBoot實(shí)現(xiàn)列表數(shù)據(jù)導(dǎo)出為Excel文件
這篇文章主要為大家詳細(xì)介紹了在Spring?Boot框架中如何將列表數(shù)據(jù)導(dǎo)出為Excel文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2024-02-02JFileChooser實(shí)現(xiàn)對(duì)選定文件夾內(nèi)圖片自動(dòng)播放和暫停播放實(shí)例代碼
這篇文章主要介紹了JFileChooser實(shí)現(xiàn)對(duì)選定文件夾內(nèi)圖片自動(dòng)播放和暫停播放實(shí)例代碼,需要的朋友可以參考下2017-04-04webuploader 實(shí)現(xiàn)圖片批量上傳功能附實(shí)例代碼
這篇文章主要介紹了webuploader 實(shí)現(xiàn)圖片批量上傳功能,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2017-11-11Java實(shí)戰(zhàn)之實(shí)現(xiàn)用戶登錄
這篇文章主要介紹了Java實(shí)戰(zhàn)之實(shí)現(xiàn)用戶登錄,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)java的小伙伴們有非常好的幫助,需要的朋友可以參考下2021-04-04spring?boot?executable?jar/war?原理解析
spring boot里其實(shí)不僅可以直接以 java -jar demo.jar的方式啟動(dòng),還可以把jar/war變?yōu)橐粋€(gè)可以執(zhí)行的腳本來啟動(dòng),比如./demo.jar,這篇文章主要介紹了spring?boot?executable?jar/war?原理,需要的朋友可以參考下2023-02-02SpringBoot如何實(shí)現(xiàn)一個(gè)實(shí)時(shí)更新的進(jìn)度條的示例代碼
本文詳細(xì)的介紹了SpringBoot如何實(shí)現(xiàn)一個(gè)實(shí)時(shí)更新的進(jìn)度條,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05Java中ThreadLocal避免內(nèi)存泄漏的方法詳解
ThreadLocal是Java中的一個(gè)線程本地存儲(chǔ)機(jī)制,它允許每個(gè)線程擁有一個(gè)獨(dú)立的本地存儲(chǔ)空間,用于存儲(chǔ)該線程的變量,本文主要介紹了ThreadLocal如何避免內(nèi)存泄漏,需要的朋友可以參考下2023-05-05Spring Boot快速實(shí)現(xiàn) IP地址解析的示例詳解
這篇文章主要介紹了Spring Boot快速實(shí)現(xiàn)IP地址解析,本文通過示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-08-08