java編程學(xué)習(xí):一篇文章了解 Java 反射和應(yīng)用

什么是反射

反射就是指程序在運(yùn)行的時(shí)候可以知道一個(gè)類的自身信息呐馆。

對(duì)于任何一個(gè)類:可以知道這個(gè)類的屬性和方法吱抚。

對(duì)于任何一個(gè)對(duì)象:可以調(diào)用這個(gè)對(duì)象的任何一個(gè)方法和屬性昔驱。

反射就是把java類中的各種成分映射成一個(gè)個(gè)的Java對(duì)象

例如:一個(gè)類有:成員變量、方法洛史、構(gòu)造方法惯殊、包等等信息,利用反射技術(shù)可以對(duì)一個(gè)類進(jìn)行?解剖也殖,把個(gè)個(gè)?組成部分映射成一個(gè)個(gè)對(duì)象土思。

(其實(shí):一個(gè)類中這些成員方法、構(gòu)造方法忆嗜、在加入類中都有一個(gè)類來描述)

反射的功能

在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類

在運(yùn)行的時(shí)候構(gòu)造任意一個(gè)類的對(duì)象

在運(yùn)行時(shí)判斷一個(gè)類所具有的成員變量和方法

在運(yùn)行時(shí)調(diào)用任何一個(gè)對(duì)象的方法

生成動(dòng)態(tài)代理(會(huì)有一篇關(guān)于動(dòng)態(tài)代理的文章己儒,在這里挖坑)

反射的優(yōu)點(diǎn)和缺點(diǎn)

動(dòng)態(tài)編譯和靜態(tài)編譯

反射用到的是動(dòng)態(tài)編譯,既然有動(dòng)態(tài)編譯捆毫,就會(huì)有靜態(tài)編譯

那么動(dòng)態(tài)編譯和靜態(tài)編譯又有什么區(qū)別闪湾?

靜態(tài)編譯:在編譯的時(shí)候進(jìn)確定類型,如果綁定對(duì)象成功绩卤,new?是靜態(tài)加載類途样,就編譯通過。

1 代碼示例


2 解釋

當(dāng)在Phone.java里面寫好代碼的時(shí)候濒憋,如果需要添加新的類何暇,則需要直接在文件里面修改代碼。假如需要添加一個(gè)華為手機(jī)凛驮,則我需要在Phone.java文件里面加個(gè)if語句判斷傳進(jìn)來的參數(shù)是不是"huawei",這樣增加了類之間的耦合性裆站。

當(dāng)刪除一個(gè)類的時(shí)候Phone.java編譯可能會(huì)出現(xiàn)錯(cuò)誤。??假如我刪除了小米手機(jī)這個(gè)類黔夭,phone.java文件沒有刪除if判斷語句宏胯,那么phone.java在編譯的時(shí)候則會(huì)失敗。

沒刪除Xiaomi.java編譯的時(shí)候是成功并且成功運(yùn)行



刪除Xiaomi.java編譯的時(shí)候就會(huì)失敗了本姥,因?yàn)閄iaomi.java不存在



動(dòng)態(tài)編譯:在運(yùn)行的時(shí)候確定類型胳嘲,綁定對(duì)象。最大發(fā)揮了Java的多態(tài)扣草,降低類之間的耦合性了牛。

1 代碼示例

Phone.java


2 解釋

(1)對(duì)比靜態(tài)編譯颜屠,當(dāng)我們需要往Phone.java里面?zhèn)鬟f新的類參數(shù)的時(shí)候,根本不需要修改Phone.java的代碼鹰祸,因?yàn)檫@里應(yīng)用了Java的多態(tài)甫窟。只要新建一個(gè)新的類實(shí)現(xiàn)了PhoneInterface的接口,把類名傳進(jìn)去就可以調(diào)用蛙婴。這里體現(xiàn)了?需要哪個(gè)類的對(duì)象就動(dòng)態(tài)的創(chuàng)建哪個(gè)類的對(duì)象粗井,也就是說動(dòng)態(tài)的實(shí)現(xiàn)了類的加載。


(2)當(dāng)刪除一個(gè)類的時(shí)候街图,Phone.java文件不會(huì)編譯失敗浇衬。

比如說刪除OnePlus.java



區(qū)別:這里說明了動(dòng)態(tài)加載的在不修改Phone.java的前提下不會(huì)因?yàn)槠渌惖牟淮嬖诙鴮?dǎo)致整個(gè)文件不能編譯,而靜態(tài)加載則會(huì)編譯的時(shí)候綁定對(duì)象餐济,從而導(dǎo)致編譯失敗耘擂。

優(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í)行相同的操作。

Class類和類類型

Class類

所有的類是java.lang.Class類的對(duì)象埠忘,Class類是所有類的類脾拆,反射的基礎(chǔ)馒索。

Class對(duì)象(類類型)

普通類構(gòu)造對(duì)象是:Student?s?=?new?Student();

但Class對(duì)象則不是,看Class類的源碼名船,構(gòu)造器是私有的绰上,則用戶無法直接像普通類那樣new一個(gè)Class的對(duì)象,只有JVM才可以構(gòu)造Class對(duì)象渠驼。

private Class(ClassLoader loader) { // Initialize final field for classLoader. The initialization value of non-null // prevents future JIT optimizations from assuming this final field is null. classLoader = loader; }

但是我們可以通過一個(gè)已知的類獲得Class對(duì)象

有以下三種方式:

Class s = Student.class;

Class s1 = new Student().getClass();

Class s2 = Class.forName("Student");

Class對(duì)象就是類類型蜈块,在這里表示的是Student類的類型,下面看一個(gè)圖了解Class對(duì)象是什么和類在JVM中加載的過程

由圖中可以看出迷扇,一個(gè)具體的Class對(duì)象就保存了具體類的基本屬性和方法百揭,并且可以調(diào)用。

Student類


反射相關(guān)操作

文章開始說過蜓席,反射會(huì)把一個(gè)類的成分(成員變量器一,方法,構(gòu)造器)各自映射成一個(gè)個(gè)對(duì)象(Field對(duì)象瓮床,Method對(duì)象盹舞,Construct對(duì)象),

一個(gè)類中這些成員方法隘庄、構(gòu)造方法踢步、在加入類中都有一個(gè)類來描述。

java.lang.reflect.Constructor; java.lang.reflect.Field;? java.lang.reflect.Method;? java.lang.reflect.Modifier;

通過Class對(duì)象我們可以做什么呢丑掺?

獲取成員方法Method

獲取成員變量Field

獲取構(gòu)造函數(shù)Construct

獲取成員方法

用法

例子

結(jié)果


只要知道包的限定名获印,就可以對(duì)Student這個(gè)類進(jìn)行所有操作

獲取成員變量信息

成員變量 = 成員類型+變量名

用法

獲取成員變量,通過Class類的以下方法街州,變量是成員變量名


例子

獲取構(gòu)造函數(shù)信息

獲取構(gòu)造函數(shù)兼丰,Class的方法如下

用法



例子

Student類的私有構(gòu)造函數(shù)

獲取私有的構(gòu)造函數(shù),并且設(shè)置為public從而可以創(chuàng)建對(duì)象


結(jié)果


實(shí)現(xiàn)對(duì)數(shù)據(jù)庫增唆缴,查鳍征。

原理

保存數(shù)據(jù)時(shí):把pojo類的屬性取出來,拼湊sql語句

查詢數(shù)據(jù)的時(shí):把查詢到的數(shù)據(jù)包裝成一個(gè)Java對(duì)象

一張數(shù)據(jù)表對(duì)應(yīng)java的一個(gè)pojo對(duì)象面徽,表中的每一個(gè)字段(column)對(duì)應(yīng)pojo的每一個(gè)屬性

數(shù)據(jù)表名和Pojo的類名相等艳丛,column和pojo的屬性相等,不區(qū)分大小寫(數(shù)據(jù)庫中不區(qū)分大小寫)

pojo的每一個(gè)屬性的get和set方法趟紊,都是為了后續(xù)的操作

實(shí)例

數(shù)據(jù)表User


pojo User類

package dbtest;

public class User {

? ? private int id;

? ? private String name;

? ? private String pwd;

? ? private int age;

? ? @Override

publicStringtoString()

{

? ? ? ? return "User{" +

? ? ? ? ? ? ? ? "id=" + id +

? ? ? ? ? ? ? ? ", name='" + name + '\'' +

? ? ? ? ? ? ? ? ", pwd='" + pwd + '\'' +

? ? ? ? ? ? ? ? ", age=" + age +

? ? ? ? ? ? ? ? '}';

? ? }

? ? publicintgetId(){

? ? ? ? return id;

? ? }

? ? publicvoidsetId(intid){

? ? ? ? this.id = id;

? ? }

? ? publicStringgetName(){

? ? ? ? return name;

? ? }

? ? publicvoidsetName(String name){

? ? ? ? this.name = name;

? ? }

? ? publicStringgetPwd(){

? ? ? ? return pwd;

? ? }

? ? publicvoidsetPwd(String pwd){

? ? ? ? this.pwd = pwd;

? ? }

? ? publicintgetAge(){

? ? ? ? return age;

? ? }

? ? publicvoidsetAge(intage){

? ? ? ? this.age = age;

? ? }

}


數(shù)據(jù)庫連接的工廠類

操作數(shù)據(jù)庫的dao

package dbtest;

import org.springframework.web.bind.annotation.ResponseBody;

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.sql.*;

import java.util.ArrayList;

import java.util.List;

public class SqlSession {

? ? publicstaticStringgetSaveObjectSql(Object o)throws InvocationTargetException, IllegalAccessException{

? ? ? ? String sql = "insert into ";

? ? ? ? /*獲取Class對(duì)象*/

? ? ? ? Class c = o.getClass();

? ? ? ? /*獲取pojo所有的方法*/

? ? ? ? Method[] methods = c.getDeclaredMethods();

? ? ? ? /*獲取全類名*/

? ? ? ? String cName = c.getName();

? ? ? ? /*通過全類名獲取數(shù)據(jù)庫名稱*/

? ? ? ? String tableName = cName.substring(cName.lastIndexOf(".")+1,cName.length());

? ? ? ? sql+= tableName + "(";

? ? ? ? /*字段名字*/

? ? ? ? List<String> fieldList = new ArrayList<>();

? ? ? ? /*字段對(duì)應(yīng)的值*/

? ? ? ? List valueList = new ArrayList();

? ? ? ? /*遍歷Class對(duì)象的Method對(duì)象氮双,就可以執(zhí)行相對(duì)于的方法了*/

? ? ? ? for?(Method?method?:

? ? ? ? ? ? ? ? methods) {

? ? ? ? ? ? String methodName = method.getName();

? ? ? ? ? ? /*找出get方法,并設(shè)置值*/

? ? ? ? ? ? if(methodName.startsWith("get")?&&?!method.equals("getClass")){

? ? ? ? ? ? ? ? String fieldName = methodName.substring(3,methodName.length());

? ? ? ? ? ? ? ? fieldList.add(fieldName);

? ? ? ? ? ? ? ? Object res = method.invoke(o,null);

? ? ? ? ? ? ? ? if(res instanceof String){

? ? ? ? ? ? ? ? ? ? valueList.add("\""+res+"\"");

? ? ? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? ? ? valueList.add(res);

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? /*拼接sql語句的字段*/

? ? ? ? for (int i = 0; i <fieldList.size() ; i++) {

? ? ? ? ? ? if(i < fieldList.size() - 1){

? ? ? ? ? ? ? ? sql += fieldList.get(i) + ",";

? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? sql += fieldList.get(i) + ") values (";

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? /*拼接sql語句的值*/

? ? ? ? for (int i = 0; i <valueList.size() ; i++) {

? ? ? ? ? ? if(i < valueList.size()-1){

? ? ? ? ? ? ? ? sql += valueList.get(i) + ",";

? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? sql += valueList.get(i) + ")";

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return sql;

? ? }

? ? /*保存數(shù)據(jù)的操作*/

? ? publicintsaveObject(Object o)throws InvocationTargetException, IllegalAccessException, SQLException{

? ? ? ? Connection connection = ConnectDBFactory.getDBConnection();

? ? ? ? String sql = getSaveObjectSql(o);

? ? ? ? PreparedStatement statement = connection.prepareStatement(sql);

? ? ? ? int i = 0;

? ? ? ? i = statement.executeUpdate();

? ? ? ? return i;

? ? }

? ? /*

* 查詢數(shù)據(jù)霎匈,查詢出來的數(shù)據(jù)映射到pojo的每一個(gè)屬性上

* */

? ? publicObjectgetObject(String pname,intid)throws ClassNotFoundException{

? ? ? ? /*通過包名獲取數(shù)據(jù)表名*/

? ? ? ? String tableName =? pname.substring(pname.lastIndexOf(".")+1,pname.length());

? ? ? ? String sql = "select * from " + tableName + " where Id = " + id;

? ? ? ? Connection conn = ConnectDBFactory.getDBConnection();

? ? ? ? Class c = Class.forName(pname);

? ? ? ? Object obj = null;

? ? ? ? try{

? ? ? ? ? ? Statement statement = conn.createStatement();

? ? ? ? ? ? ResultSet resultSet = statement.executeQuery(sql);

? ? ? ? ? ? Method[] methods = c.getDeclaredMethods();

? ? ? ? ? ? while(resultSet.next()){

? ? ? ? ? ? ? ? obj = c.newInstance();

? ? ? ? ? ? ? ? for?(Method?method?:methods

? ? ? ? ? ? ? ? ? ? ? ? ) {

? ? ? ? ? ? ? ? ? ? String methodName = method.getName();

? ? ? ? ? ? ? ? ? ? if(methodName.startsWith("set")){

? ? ? ? ? ? ? ? ? ? ? ? /*通過方法名獲取數(shù)據(jù)庫的列名*/

? ? ? ? ? ? ? ? ? ? ? ? String columnName = methodName.substring(3,methodName.length());

? ? ? ? ? ? ? ? ? ? ? ? /*獲取參數(shù)的類型*/

? ? ? ? ? ? ? ? ? ? ? ? Class[] params = method.getParameterTypes();

? ? ? ? ? ? ? ? ? ? ? ? /*判斷參數(shù)的類型*/

? ? ? ? ? ? ? ? ? ? ? ? if(params[0] == String.class){

? ? ? ? ? ? ? ? ? ? ? ? ? ? method.invoke(obj,resultSet.getString(columnName));

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? if(params[0] == int.class){

? ? ? ? ? ? ? ? ? ? ? ? ? ? method.invoke(obj,resultSet.getInt(columnName));

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }catch (Exception e){

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? ? ? return obj;

? ? }

? ? publicstaticvoidmain(String[] args){

? ? ? ? try{

? ? ? ? ? ? SqlSession session = new SqlSession();

? ? ? ? ? ? User user = new User();

? ? ? ? ? ? user.setAge(22);

? ? ? ? ? ? user.setName("JiemingLi");

? ? ? ? ? ? user.setId(44);

? ? ? ? ? ? user.setPwd("123456");

? ? ? ? ? ? int resNum? = session.saveObject(user);

? ? ? ? ? ? if(resNum > 0){

? ? ? ? ? ? ? ? System.out.println("成功");

? ? ? ? ? ? }else{

? ? ? ? ? ? ? ? System.out.println("插入失敗");

? ? ? ? ? ? }

? ? ? ? ? ? User res = (User)session.getObject("dbtest.User",44);

? ? ? ? ? ? System.out.println(res);

? ? ? ? }catch (Exception e){

? ? ? ? ? ? e.printStackTrace();

? ? ? ? }

? ? }

}

結(jié)果


總結(jié)

Java反射非常好用戴差,靈活性非常大,不用花費(fèi)太多的時(shí)間去寫操作數(shù)據(jù)庫的代碼铛嘱,讓重點(diǎn)在開發(fā)者的業(yè)務(wù)邏輯上∨停現(xiàn)在很多和數(shù)據(jù)庫操作的框架都用到反射袭厂,只要配置文件,按照框架的規(guī)則就可以對(duì)數(shù)據(jù)庫進(jìn)行相對(duì)應(yīng)的操作了球匕。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嵌器,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谐丢,更是在濱河造成了極大的恐慌爽航,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,386評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乾忱,死亡現(xiàn)場(chǎng)離奇詭異讥珍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)窄瘟,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評(píng)論 3 394
  • 文/潘曉璐 我一進(jìn)店門衷佃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人蹄葱,你說我怎么就攤上這事氏义。” “怎么了图云?”我有些...
    開封第一講書人閱讀 164,704評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵惯悠,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我竣况,道長(zhǎng)克婶,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,702評(píng)論 1 294
  • 正文 為了忘掉前任丹泉,我火速辦了婚禮情萤,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘摹恨。我一直安慰自己筋岛,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評(píng)論 6 392
  • 文/花漫 我一把揭開白布晒哄。 她就那樣靜靜地躺著睁宰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪揩晴。 梳的紋絲不亂的頭發(fā)上勋陪,一...
    開封第一講書人閱讀 51,573評(píng)論 1 305
  • 那天贪磺,我揣著相機(jī)與錄音硫兰,去河邊找鬼。 笑死寒锚,一個(gè)胖子當(dāng)著我的面吹牛劫映,可吹牛的內(nèi)容都是我干的违孝。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼泳赋,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼雌桑!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起祖今,我...
    開封第一講書人閱讀 39,230評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤校坑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后千诬,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體耍目,經(jīng)...
    沈念sama閱讀 45,680評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評(píng)論 3 336
  • 正文 我和宋清朗相戀三年徐绑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了邪驮。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡傲茄,死狀恐怖毅访,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情盘榨,我是刑警寧澤喻粹,帶...
    沈念sama閱讀 35,706評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站草巡,受9級(jí)特大地震影響磷斧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜捷犹,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評(píng)論 3 330
  • 文/蒙蒙 一弛饭、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧萍歉,春花似錦侣颂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至蔑舞,卻和暖如春拒担,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背攻询。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評(píng)論 1 270
  • 我被黑心中介騙來泰國打工从撼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人钧栖。 一個(gè)月前我還...
    沈念sama閱讀 48,158評(píng)論 3 370
  • 正文 我出身青樓低零,卻偏偏與公主長(zhǎng)得像婆翔,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掏婶,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容