java反射機制精講
目錄
1.反射機制的概念
2.反射的根底Class類
3.反射的用法
4.反射的使用示例
作者簡介:全棧學習筆記,一個正在盡力的人
反射機制的概念:
在運轉狀況中,關于恣意一個類,都能夠獲取到這個類的一切特點和辦法,關于恣意一個目標,都能夠調(diào)用它的恣意一個辦法和特點(包含私有的辦法和特點),這種動態(tài)獲取的信息以及動態(tài)調(diào)用目標的辦法的功用就稱為java言語的反射機制。反射被視為動態(tài)言語的要害。簡略來說反射便是java的各種成分映射成對應的java類。
淺顯點講,經(jīng)過反射,該類對咱們來說是徹底通明的,想要獲取任何東西都能夠。包含結構辦法,特點,辦法。
java反射機制供給的功用:
在運轉時判斷恣意一個目標所屬的類;
在運轉時結構恣意一個類的目標;
在運轉時判斷恣意一個類所具有的成員變量和辦法;
在運轉時調(diào)用恣意一個目標的辦法;
生成動態(tài)代理。
這其實也涉及到了言語的動態(tài)與靜態(tài),java言語本身不算是動態(tài)言語,可是他有一個十分突出的動態(tài)機制,便是咱們所說的反射機制。
什么是動態(tài)言語呢?便是說,程序在運轉的時分,(注意是運轉的時分,不是編譯的時分)答應改變程序結構或許變量類型。反之靜態(tài)便是沒有這些特點了。
反射的根底Class類
Class類是反射完成的根底,所以想要學會反射,必須先把握Class類的一些根本的概念。
類是什么?類是Class類的實例目標,所以說Class類是一切類的類。
要想解剖一個類,必須先獲取到該類的字節(jié)碼文件目標。而解剖運用的便是Class類中的辦法,所以先要獲取每一個字節(jié)碼文件對應的Class類型的目標。
Class類沒有公共的結構辦法,Class目標是在類加載的時分由Java虛擬機以及經(jīng)過調(diào)用類加載器中的defineClass辦法自動結構的,因此不能顯式地聲明一個Class目標。這兒又涉及到一個東西,類的加載
扼要的說明一下:
類加載器:當程序需要是用某個類時,假如該類還沒有被加載到內(nèi)存中,則,體系會經(jīng)過加載,銜接,初始化這三步來對類進行初始化
加載:便是指將class文件讀入內(nèi)存(編譯之后的文件是.class文件),并為之創(chuàng)立一個Class目標
任何類被運用時,體系都會樹立一個Class目標,第一次的時分會,第二次則會判斷這個類是否存在。
銜接:驗證是否有正確的內(nèi)部結構,并和其他類協(xié)調(diào)一致
準備為類的靜態(tài)成員分配內(nèi)存,并設置默認初始化值
并做一個解析:將類的二進制數(shù)據(jù)中的字符引證替換為直接引證。
上面提到Class目標是不能直接創(chuàng)立的,可是咱們能夠經(jīng)過其他辦法得到Class類的,現(xiàn)在有三種辦法能夠得到咱們想要的Class類,得到Class類之后就能正常的運用反射了。
獲取Class的三種辦法(獲取一個類的字節(jié)碼目標):
第一種:運用目標獲取,運用目標的getClass獲取
Personperson=newPerson();Classclazz=person.getClass();
第二種:運用靜態(tài)特點class
Classclazz=Person.class
第三種:運用Class類的靜態(tài)辦法forName(字符串的類名)
注;類名要寫全包名
Classclazz=Calss.forName(“…….”);
好了,要點來了,反射怎樣玩才風趣!
反射的用法
上面說了經(jīng)過反射能夠得到恣意一個類的什么什么,下面來看看是不是真的。
第一步要干啥?當然是經(jīng)過之前的哪三種辦法來得到這個能夠為所欲為的Class類。有三種辦法,咱們先都做個示例吧!
上代碼
//獲取Class第一種辦法Studentstudent=newStudent();
Classclazz=student.getClass();//獲取Class第二種辦法ClassclazzTwo=Student.class;//獲取Class第三種辦法ClassclazzThree=Class.forName(“demo.qzxxbj.entity.Student”);
System.out.println(“第一個”+clazz+”\n第二個”+clazzTwo+”\n第三個”+clazzThree);
成果
第一個classdemo.qzxxbj.entity.Student第二個classdemo.qzxxbj.entity.Student第三個classdemo.qzxxbj.entity.Student
能夠看到三種辦法得到的Class目標是相同的,沒有差異。
第三種辦法是會有一個找不到類的反常拋出的。
其間Student便是一個簡略的類,能夠是任何類。
經(jīng)過Class獲取恣意一個類的特點
Student類的代碼
packagedemo.qzxxbj.entity;/**
*@author微信大眾號:全棧學習筆記
*@date2020/3/29
*@description*/publicclassStudent{privateStringname;privateIntegerage;privateStringsex;publicintnumber;publicintgetNumber(){returnnumber;
}publicvoidsetNumber(intnumber){this.number=number;
}publicStringgetName(){returnname;
}publicvoidsetName(Stringname){this.name=name;
}publicIntegergetAge(){returnage;
}publicvoidsetAge(Integerage){this.age=age;
}publicStringgetSex(){returnsex;
}publicvoidsetSex(Stringsex){this.sex=sex;
}
}
以下獲取Class的辦法都采用第二種,比較簡潔
//獲取Class第二種辦法ClassclazzTwo=Student.class;//獲取該類指定特點名的public成員變量,包含父類的Fieldfield=clazzTwo.getField(“number”);//fieldpublicintdemo.qzxxbj.entity.Student.numberSystem.out.println(“該類指定特點名的public成員變量,包含父類的”+field);//獲取該類指定稱號聲明的變量,即不包含父類的FielddeField=clazzTwo.getDeclaredField(“name”);//deFieldprivatejava.lang.Stringdemo.qzxxbj.entity.Student.nameSystem.out.println(“該類一切聲明的變量,即不包含父類的”+deField);//獲取該類一切的public聲明的成員變量Fieldfields[]=clazzTwo.getFields();System.out.println(“public聲明的變量:”);//publicintdemo.qzxxbj.entity.Student.numberfor(Fieldfield1:fields){System.out.println(field1);
}//獲取該目標的一切成員變量FielddeFields[]=clazzTwo.getDeclaredFields();System.out.println(“該目標的一切成員變量”);//privatejava.lang.Stringdemo.qzxxbj.entity.Student.name//privatejava.lang.Integerdemo.qzxxbj.entity.Student.age//privatejava.lang.Stringdemo.qzxxbj.entity.Student.sex//publicintdemo.qzxxbj.entity.Student.numberfor(Fieldfield1:deFields){System.out.println(field1);
}
記住getFields(),getField(Stringname),getDeclaredFields(),getDeclaredField(Stringname)的差異,你就能好好把握這個知識點!
經(jīng)過Class獲取恣意成員辦法
仍是看代碼吧!
獲取成員辦法Method
//獲取Class第二種辦法ClassclazzTwo=Student.class;//根據(jù)辦法名以及參數(shù)類型獲取,只能獲取public聲明的辦法,包含父類的Methodmethod=clazzTwo.getMethod(“setAge”,Integer.class);//publicjava.lang.Integerdemo.qzxxbj.entity.Student.getAge()System.out.println(method);//根據(jù)辦法名以及參數(shù)稱號獲取該類聲明的一切的特點辦法,不包含父類的MethoddeMethod=clazzTwo.getDeclaredMethod(“setAge”,Integer.class);System.out.println(deMethod);//獲取該目標聲明的一切的public辦法,包含父類的Methodmethods[]=clazzTwo.getMethods();//獲取該目標聲明的一切的辦法,可是不包含父類的辦法MethoddeMethods[]=clazzTwo.getDeclaredMethods();
一個Method辦法打印出來是什么呢?上面代碼中也包含了
publicvoiddemo.qzxxbj.entity.Student.setAge(java.lang.Integer)
和之前講的Field是不是很相似。
既然提到了辦法,那么就必定涉及到了辦法調(diào)用,咱們得到了這些辦法,又該怎樣調(diào)用這個類里邊的辦法呢?運用invoke函數(shù),Method這個類里邊包含了一個invoke函數(shù),英語好的就知道了,這個invoke的中文意思便是“調(diào)用”。
怎樣用呢?
//獲取Class第二種辦法ClassclazzTwo=Student.class;//根據(jù)辦法名以及參數(shù)類型獲取,只能獲取public聲明的辦法,包含父類的Methodmethod=clazzTwo.getMethod(“setAge”,Integer.class);//publicjava.lang.Integerdemo.qzxxbj.entity.Student.getAge()System.out.println(method);//使用Class創(chuàng)立一個目標的實例Studentstudent=(Student)clazzTwo.newInstance();//函數(shù)調(diào)用Objectvalue=method.invoke(student,20);//nullSystem.out.println(value);
以上的代碼,你可能會看不懂,我來講一下,首要,咱們獲取一個類的Class,然后咱們經(jīng)過這個Class獲取該類的一個setAge辦法,獲取到這個辦法后繼續(xù)調(diào)用這個辦法,調(diào)用辦法是不是應該調(diào)用一個實例目標里邊的辦法?所以咱們需要先實例化一個目標,經(jīng)過什么辦法呢,經(jīng)過class里邊的newInstance(),創(chuàng)立一個實例,這種辦法需要該實例化的類具有一個無參結構辦法。還有其他辦法也能創(chuàng)立一個實例,后邊咱們會說。創(chuàng)立出一個實例目標之后,咱們就能開始調(diào)用辦法了。
經(jīng)過invoke對辦法進行調(diào)用,invoke的第一個參數(shù)便是一個實例化目標,不然我去哪找這個辦法。第二個參數(shù),或許第三個,等等,后邊的一切參數(shù)都是我調(diào)用的該辦法所具有的參數(shù),按照次序填進去就OK了。然后這個函數(shù)回來的是一個Object目標,你都能想到,我調(diào)用一個辦法是不是要讓他做一些事,做了這些事需要回來一個東西,不知道這個東西是啥,就用Object獲取嘛。因為咱們調(diào)用的這個辦法不需要回來值,所以便是null了。很簡略是不是。學到了記得給我點個關注哦!精彩美文第一時間推送到你的手中。
經(jīng)過Class獲取結構辦法
這個被我放到了最后來學習,畢竟我覺得用的份額比較少。一起來學習一下怎樣用Class獲取結構辦法,并調(diào)用他。
publicStudent(Stringname,intid){this.name=name;this.id=id;
}
這兒咱們在Student類里邊添加了一個結構辦法。
然后咱們來獲取這個結構辦法。
//獲取Class第二種辦法ClassclazzTwo=Student.class;//獲取無參結構辦法,public聲明的,包含父類,加上參數(shù)時便是獲取特定的結構辦法Constructorconstructor=clazzTwo.getConstructor();//publicdemo.qzxxbj.entity.Student()System.out.println(constructor);//獲取該類一切的public聲明的結構辦法Constructorconstructors[]=clazzTwo.getConstructors();//獲取指定參數(shù)的結構辦法ConstructordeConstructor=clazzTwo.getDeclaredConstructor(String.class,Integer.class);//獲取一切的該類的結構辦法,不包含父類的ConstructordeConstructors[]=clazzTwo.getDeclaredConstructors();
上面代碼應該很簡單看懂吧,我就不細說了。這兒說一下怎樣運用得到的結構辦法,結構辦法顧名思義便是來實例化目標的,上面咱們也有提到怎樣經(jīng)過Class實例化一個目標,現(xiàn)在咱們來經(jīng)過結構方辦法實例化一個目標
Studentstudent=(Student)deConstructor.newInstance(“全棧學習筆記”,21);//21System.out.println(student.getAge());
現(xiàn)在知道了吧,咱們差不都將反射的功用講完了,就差一個反射的動態(tài)代理,這個比較重要,會專門出一篇博客,碼字不易。希望點個關注。微信大眾號:全棧學習筆記,精彩美文每天為你推送。
最后我根據(jù)我自己曾經(jīng)的經(jīng)歷寫了一個java反射的sql語句拼接,適當于是一個反射的使用吧。
反射的使用示例
經(jīng)過反射動態(tài)的生成SQL語句,是不是也有點牛逼的感覺?
直接上代碼吧,我只發(fā)一個SQL語句,感興趣的能夠私信我找我拿完整的代碼!
publicStringinsert(Objectobject)throwsIllegalAccessException,NoSuchMethodException,InvocationTargetException{`//insertintostudent(id,name,sex)values(1,”全棧學習筆記”,”男”)StringBuildersql=newStringBuilder();
Classclazz=object.getClass();
sql.append(“insertinto”);
sql.append(clazz.getSimpleName()+”(“);
Field[]fields=clazz.getDeclaredFields();for(Fieldfield:fields){
sql.append(field.getName()+”,”);
}
sql.deleteCharAt(sql.length()-1);
sql.append(“)”);
sql.append(“values(“);for(Fieldfield:fields){
field.setAccessible(true);Objectvalue=field.get(object);StringfieldName=field.getName();Stringstr1=fieldName.substring(0,1).toUpperCase();Stringstr2=fieldName.substring(1,fieldName.length());StringstrValue=str1.concat(str2);//StringstrValue=fieldName.substring(0,1).toUpperCase().concat(fieldName.substring(1,fieldName.length()));Methodmethod=clazz.getMethod(“get”+strValue,null);Objectvalue1=method.invoke(object,null);//if(value1.getClass().equals(String.class))//if(field.getType().equals(String.class))if(value1instanceofString){
sql.append(“\””).append(value1).append(“\””).append(“,”);
}else{
sql.append(value1).append(“,”);
}
}
sql.deleteCharAt(sql.length()-1);
sql.append(“)”);
System.out.println(sql.toString());returnsql.toString();
}
廣州天河區(qū)珠江新城富力盈力大廈北塔2706
020-38013166(網(wǎng)站咨詢專線)
400-001-5281 (售后服務熱線)
深圳市坂田十二橡樹莊園F1-7棟
Site/ http://www.szciya.com
E-mail/ itciya@vip.163.com
品牌服務專線:400-001-5281
長沙市天心區(qū)芙蓉中路三段398號新時空大廈5樓
聯(lián)系電話/ (+86 0731)88282200
品牌服務專線/ 400-966-8830
旗下運營網(wǎng)站:
Copyright ? 2016 廣州思洋文化傳播有限公司,保留所有權利。 粵ICP備09033321號