Java中的反射的应用
在正常情況下,需要先有一個(gè)類的完整路徑引入之后才可以按照固定的格式產(chǎn)生實(shí)例話對(duì)象,但是在Java中也允許通過(guò)一個(gè)實(shí)例話對(duì)象找到一個(gè)類的完整信息。那么這就是Class類的功能。
實(shí)際上類是Java反射的源頭,實(shí)際上所謂反射從程序的運(yùn)行結(jié)果來(lái)看也很好理解,即可以通過(guò)對(duì)象的反射求出類的名稱。
?
實(shí)例化Class類,獲得字節(jié)碼文件的方法有三種:
- 第一種:通過(guò)forName()方法;
- 第二種:類.class
- 第三種:對(duì)象.getClass()
package toto.learn;
class X1{}
publicclass GetClassDemo02 {
?
??? publicstaticvoid main(String[] args) {
?????? Class<?> c1=null;//指定泛型
?????? Class<?> c2=null;//指定泛型
?????? Class<?> c3=null;//指定泛型
?????? try{
?????????? c1=Class.forName("toto.learn.X");//最常用的形式,這種方式將字節(jié)碼文件加載到內(nèi)存中。
?????? }catch(ClassNotFoundException e){
?????????? e.printStackTrace();
?????? }
?????? c2 = new X1().getClass();//通過(guò)Object類中的方法實(shí)例
?????? c3 = X1.class;//通過(guò)類class實(shí)例化
?????? System.out.println("類名稱:"+c1.getName());//得到類的名稱
?????? System.out.println("類名稱:"+c2.getName());//得到類的名稱
?????? System.out.println("類名稱:"+c3.getName());//得到類的名稱
??? }
}
?
通過(guò)以上方法獲得類名稱的方式得到的是包名+類名
?
如果要想通過(guò)Class類本身實(shí)例化其他類的對(duì)象,則可以使用newInstance()方法,但是必須要保證被實(shí)例化的類中必須存在一個(gè)無(wú)參夠造方法。
?
被實(shí)例化對(duì)象的類中必須存在無(wú)參構(gòu)造方法,如果不存在的話,則肯定是無(wú)法實(shí)例化的。
?
1、 通過(guò)Class類中的getConstructors()取得本類中的全部構(gòu)造方法
2、 向構(gòu)造方法中傳遞一個(gè)對(duì)象數(shù)組進(jìn)去,里面包含了構(gòu)造方法中所需的各個(gè)參數(shù)
3、 之后通過(guò)Constructor實(shí)例化對(duì)象。
?
package org.lxh.demo15.instancedemo;
import java.lang.reflect.Constructor;
publicclass InstanceDemo03 {
??? publicstaticvoid main(String[] args) {
?????? Class<?> c = null;
?????? try {
?????????? c = Class.forName("org.lxh.demo15.instancedemo.Person");??? // 聲明Class對(duì)象
?????? } catch (ClassNotFoundException e) {
?????????? e.printStackTrace();
?????? }
?????? Person per = null;????????? // 聲明Person對(duì)象
?????? Constructor<?> cons[] = null; ? // 聲明一個(gè)表示構(gòu)造方法的數(shù)組
?????? cons = c.getConstructors();? // 通過(guò)反射,取得全部構(gòu)造
?????? try {// 向構(gòu)造方法中傳遞參數(shù),此方法使用可變參數(shù)接收,并實(shí)例化對(duì)象
?????????? per = (Person) cons[0].newInstance("李興華", 30);
?????? } catch (Exception e) { // 因?yàn)橹挥幸粋€(gè)構(gòu)造,所以數(shù)組下標(biāo)為0
?????????? e.printStackTrace();
?????? }
?????? System.out.println(per); ?????? // 輸出對(duì)象
??? }
}
?
per = (Person)cons[0].newInstance("李興華", 30); //此處是調(diào)用并使用構(gòu)造方法的部分。
?
在聲明對(duì)象數(shù)組的時(shí)候,必須考慮到構(gòu)造方法中參數(shù)的類型順序,所以第一個(gè)參數(shù)的類型為Stirng,第二個(gè)參數(shù)的類型WieInteger(在使用是可以自動(dòng)拆箱)
Constructor<?>cons[]=null;//實(shí)例化構(gòu)造方法的數(shù)組
Cons =c.getConstructors();//取得全部構(gòu)造
//向構(gòu)造方法中傳遞參數(shù),此方使用可變參數(shù)接收,并實(shí)例化對(duì)象
Per = (Person)cons[0].newInstance(“李興華”,30);
?
設(shè)置構(gòu)造方法的參數(shù)內(nèi)容
publicPerson(String name,int age){//通過(guò)構(gòu)造設(shè)置屬性內(nèi)容
}
?
反射的應(yīng)用
可以使用反射取得實(shí)現(xiàn)的全部接口
可以使用反射取得一個(gè)類所繼承的父類
可以使用反射取得一個(gè)類中的全部構(gòu)造方法
可以使用反射取得一個(gè)類中的全部方法
可以使用反射取得一個(gè)類中的全部屬性
?
在實(shí)際開(kāi)發(fā)中發(fā),以上的程序就是反射應(yīng)用最多的地方,當(dāng)然反射機(jī)制所提供的功能遠(yuǎn)不如此,還可以通過(guò)反射得到一個(gè)類中的完整構(gòu)造,那么這就要使用到j(luò)ava.lang.reflect包中的一下幾個(gè)類。
Constructor:表示類中的構(gòu)造方法
Field:表示類中的屬性
Method:表示類中的方法
?
這三個(gè)類都是AccessibleObject類中的子類。
?
要想取得一個(gè)類中所實(shí)現(xiàn)的全部接口,則必須使用Class類中的getInterfaces()方法。此方法定義如下:
publicClass[] getInterfaces();
此方法返回一個(gè)Class類的對(duì)象數(shù)組,之后就可以直接利用Class類中的getName()方法輸出即可。
?
?
通過(guò)反射取得實(shí)現(xiàn)的全部接口
package org.lxh.demo15;
?
publicclass GetInterfaceDemo {
?
??? publicstaticvoid main(String[] args) {
?????? Class<?> c1 =null;//聲明Class對(duì)象
?????? try{
?????????? c1 = Class.forName("org.lxh.demo15.Person");//實(shí)例化Class對(duì)象
?????? }catch(ClassNotFoundException e){
?????????? e.printStackTrace();
?????? }
?????? Class<?> c[] = c1.getInterfaces();//取得實(shí)現(xiàn)的全部接口
?????? for(int i=0;i<c.length;i++){
?????????? System.out.println("實(shí)現(xiàn)的接口名稱:"+c[i].getName());//輸出接口名稱
?????? }
??? }
?
}
?
一個(gè)類中可以實(shí)現(xiàn)多個(gè)接口,但是只能繼承一個(gè)父類,所以如果要想取得一個(gè)類的父類,可以直接使用Class類中的getSuperclass()方法。此方法定義如下:
?
PublicClass<? Super T> getSuperclass()
此方法返回的是Class實(shí)例,和之前的得到接口一樣,可以通過(guò)getName()方法取得名稱。
?
取得構(gòu)造方法的例子:
package org.lxh.demo15;
import java.lang.reflect.Constructor;//導(dǎo)入反射操作包
publicclass GetConstructorDemo01 {
?
??? publicstaticvoid main(String[] args) {
?????? Class<?> c1 = null;//聲明Class對(duì)象
?????? try{
?????????? c1 = Class.forName("org.lxh.demo15.Person");
?????? }catch(ClassNotFoundException e){
?????????? e.printStackTrace();
?????? }
?????? Constructor<?> con[]=c1.getConstructors();//得到全部構(gòu)造方法
?????? for(int i=0;i<con.length;i++){
?????????? System.out.println("構(gòu)造方法:"+con[i]);//直接打印輸出
?????? }
??? }
}
還原修飾符
在整個(gè)Java中對(duì)于方法的修飾符使用一定的數(shù)字表示出來(lái)的,而如果要想把這個(gè)數(shù)字還原成用戶可以看懂的關(guān)鍵字,則必須依靠Modifier類完成,此類定義在java.lang.reflect包中。直接使用Modifer類的一下方法可修飾符:
publicstatic String toString(int mod)
int? mo = con[i].getModifiers();
System.out.print(Modifier.toString(mo)+””); //還原權(quán)限
?
getDeclaredMethods()方法,此方法返回一個(gè)Method類的對(duì)象數(shù)組,而如果要想進(jìn)一步取得方法具體信息,例如:方法的參數(shù),拋出的異常聲明等等,則就是必須依靠Method類
?
再反射操作中同樣可以取得一個(gè)類中的全部屬性,但是在取得屬性的時(shí)候有以下兩種不同的操作:
得到實(shí)現(xiàn)的接口或父類中的公共屬性:public Field[] getFields() throwsSecurityException
?
得到本類中自己定義的的全部屬性:public Field[] getDeclaredFields() throws SecurityException
?
如果要使用反射調(diào)用類中的方法可以通過(guò)Method類完成,操作步驟如下:
1、 通過(guò)Class類的getMethod(Stringname,Class…parameterTypes)方法取得一個(gè)Method的對(duì)象,并設(shè)置此方法操作時(shí)所需的參數(shù)類型。
2、 之后才可以使用invoke進(jìn)行調(diào)用,并向方法中傳遞要設(shè)置的參數(shù)。
?
在Proxy類中的newProxyInstance()方法中,需要一個(gè)ClassLoader類的實(shí)例,ClassLoader實(shí)際上對(duì)應(yīng)的是類加載器,在Java中主要有以下三種類加載器:
BootstrapClassLoader:此加載器采用C++ 編寫,一般開(kāi)發(fā)中是看不到的;
ExtensionClassLoader:用來(lái)進(jìn)行擴(kuò)展類的加載,一般對(duì)應(yīng)的是jre\lib\ext目錄中的類;
AppClassLoader:加載classpath指定的類,是最常用使用的一種加載器。
?
?
通過(guò)forName()加載類兩次時(shí),此時(shí)的類只加載了一次
?
?
如果有以下代碼:
Object obj= new VipUser();//這里VipUser是User的子類,它繼承了User
if(obj instanceof User){
?????????? System.out.println("instanceof判斷是一個(gè)user");
?????????? User user = (User)obj;
?????? }
當(dāng)使用以上代碼中的instanceof來(lái)判斷時(shí),此時(shí)obj就是一個(gè)User了,但實(shí)際上它不是。它只是User的一個(gè)子類。
?
總結(jié):使用instanceof時(shí)主要用來(lái)判斷是否實(shí)現(xiàn)了后面的接口。
if(obj.getClass()==User.class){
?????????? System.out.println("getClass判斷,是一個(gè)user");
?????????? User user = (User)obj;
?????? }
而getClass()用于判斷對(duì)象的準(zhǔn)確類型。
?
在后面用到的類:
package toto.learn1;
?
publicclass User {
??? private String name;
??? private String password;
??? private String gender;
???
??? public User(String name, String password, String gender) {
?????? super();
?????? this.name = name;
?????? this.password = password;
?????? this.gender = gender;
??? }
???
??? public User() {
?????? super();
?????? // TODO Auto-generatedconstructor stub
??? }
???
??? public User(String name, String password) {
?????? super();
?????? this.name = name;
?????? this.password = password;
??? }
?
??? public String getName() {
?????? returnname;
??? }
??? publicvoid setName(String name) {
?????? this.name = name;
??? }
??? public String getPassword() {
?????? returnpassword;
??? }
??? publicvoid setPassword(String password) {
?????? this.password = password;
??? }
??? public String getGender() {
?????? returngender;
??? }
??? publicvoid setGender(String gender) {
?????? this.gender = gender;
??? }
??? publicvoid run(String str, int num){
?????? System.out.println("run");
??? }
??? publicvoid run(String name){
?????? System.out.println("hello:"+name);
??? }
}
以下是關(guān)于反射的部分。
package toto.learn1;
?
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
?
publicclass Demo2 {
?
??? /**
??? ?* 反射
??? ?* @throwsIllegalAccessException
??? ?* @throwsInstantiationException
??? ?* @throwsNoSuchMethodException
??? ?* @throwsSecurityException
??? ?*/
??? publicstaticvoid main(String[] args) throws Exception {
?????? Class clazz = User.class;
?????? //構(gòu)造方法
?????? //獲得構(gòu)造方法
?????? Constructor[] cons = clazz.getConstructors();
?????? for(Constructor con : cons){
?????????? //參數(shù)列表,獲得的約定是完整的參數(shù)類型,包括這種類型坐在的包。
?????????? Class[] types = con.getParameterTypes();
?????????? System.out.println("參數(shù)類型為:");
?????????? for(Class type:types){
????????????? System.out.println(type.getName()+"...");
?????????? }
?????????? System.out.println();
?????? }
?????? //獲得指定的構(gòu)造方法?????創(chuàng)建對(duì)象
?????? try {
?????????? Object obj = clazz.newInstance();//默認(rèn)調(diào)用無(wú)參的構(gòu)造方法
?????????? System.out.println(obj.getClass());
?????? } catch (InstantiationException e) {
?????????? e.printStackTrace();
?????? } catch (IllegalAccessException e) {
?????????? e.printStackTrace();
?????? }
?????? /**參數(shù)類型為:
?????????? java.lang.String...
?????????? java.lang.String...
??????????
?????????? 參數(shù)類型為:
?????????? java.lang.String...
?????????? java.lang.String...
?????????? java.lang.String...
??????????
?????????? class toto.learn1.User*/
?????? ?System.out.println("-------------------------");
?????? ?//獲得指定的構(gòu)造方法2 創(chuàng)建對(duì)象
?????? Object obj = clazz.newInstance();//默認(rèn)調(diào)用無(wú)參的構(gòu)造方法
?????? Constructor constructor = clazz.getConstructor(String.class,String.class);//此處調(diào)用有兩個(gè)參數(shù)的構(gòu)造方法
?????? //String.class是因?yàn)闃?gòu)造方法中有帶有年個(gè)參數(shù)的構(gòu)造方法的形參都是String類的。
?????? User usr = (User)constructor.newInstance("toto","查看");//傳遞兩個(gè)參數(shù)。
?????? System.out.println(usr.getName()+"?? "+usr.getPassword());//結(jié)果:toto?? 查看
??????????
?????? //方法
?????? //獲得類所有的方法
?????? Method [] methods = clazz.getMethods();
?????? for(Method method:methods){
?????????? System.out.println(method.getName());
?????? }
?????? /**通過(guò)getMethods()方法獲得的類中包含有父類的方法,并且拿到的是共有的方法
?????? ?*? run
?????????? run
?????????? getName
?????????? setName
?????????? getPassword
?????????? setPassword
?????????? getGender
?????????? setGender
?????????? wait
?????????? wait
?????????? wait
?????????? hashCode
?????????? getClass
?????????? equals
?????????? toString
?????????? notify
?????????? notifyAll
?????? ?* */
?????? //如果想獲得聲明的所有方法,包括非public的,不包括繼承的,可以使用一下途徑實(shí)現(xiàn)
?????? System.out.println("-----------------------");
?????? Method [] methods2 = clazz.getDeclaredMethods();
?????? for(Method method:methods2){
?????????? System.out.println(method.getName());
?????? }
?????? /**結(jié)果是:
?????? ?*? run
?????????? run
?????????? getName
?????????? setName
?????????? getPassword
?????????? setPassword
?????????? getGender
?????????? setGender*/
?????? //獲得指定的方法,調(diào)用方法
?????? Method runMethod = clazz.getMethod("run", String.class); /**第一個(gè)表示要調(diào)用那個(gè)方法
?????? 第二個(gè)參數(shù)是可變參數(shù),表示調(diào)用的潤(rùn)方法的參數(shù)類型。*/
?????? //獲得了方法后,要執(zhí)行時(shí),得給出一個(gè)對(duì)象,在這里要執(zhí)行的對(duì)象是User,故作如下實(shí)例
?????? User usr1 = new User();
?????? runMethod.invoke(usr1, "toto");//表示執(zhí)行usr1對(duì)象中的runMethod方法,并且向方法中傳遞了參數(shù)。
?????? /**
?????? ?* 運(yùn)行結(jié)果:hello:toto?此為User類中run(String name);方法輸出的結(jié)果,其中name即為toto*/
?????? //屬性
?????? //獲得對(duì)象的屬性,先創(chuàng)建一個(gè)對(duì)象
?????? Object object = new User("toto","123","male");//調(diào)用User中的構(gòu)造方法:
?????? //由于獲得對(duì)象的私有屬性,得獲得get方法,故得先獲得對(duì)象的字節(jié)碼文件,通過(guò)這個(gè)文件獲得get方法
?????? Class objectClazz = object.getClass();
?????? //獲得get方法
?????? Method runMethod2 = clazz.getMethod("getName"); //由于該方法沒(méi)有參數(shù),故不用在向里面?zhèn)鬟f參數(shù)
?????? //執(zhí)行此方法,輸出參數(shù)
?????? Object name = runMethod2.invoke(object);
?????? System.out.println(name);//由于上面?zhèn)鬟f了name值,故此處返回的結(jié)果值為:toto
?????? //獲得所有屬性
?????? System.out.println("-------------------------------");
?????? //Field[] fields =clazz.getFields();//此方法拿到的是public的屬性,由于User類中沒(méi)有共有的屬性
?????? Field[] fields = clazz.getDeclaredFields();//拿到聲明的屬性
?????? for(Field fd : fields){
?????????? System.out.println(fd.getName()+"屬性類型: "+fd.getType());
?????? }
?????? /** 結(jié)果為:
?????? ?*? name屬性類型: class java.lang.String
?????????? password屬性類型: class java.lang.String
?????????? gender屬性類型: class java.lang.String*/
?????? //為對(duì)象的password屬性賦值:
?????? User user2 = new User();
?????? String fieldName = "password";//作為變量來(lái)處理的,可以傳遞任意的屬性名稱
?????? //getpw是通過(guò)反射拿到的屬性,其實(shí)就是password
?????? Field getpw = user2.getClass().getDeclaredField(fieldName);
?????? //判斷屬性是否為私有:
?????? int num = getpw.getModifiers();//返回的是整型的值。
?????? if(num == Modifier.PRIVATE){//獲得的是
?????????? System.out.println("屬性是私有的");
?????? //讓java虛擬機(jī)不檢查訪問(wèn)權(quán)限
?????? //getpw.setAccessible(true);
?????? }
?????? //System.out.println(getpw);//結(jié)果private java.lang.Stringtoto.learn1.User.password
?????? getpw.set(user2, 234567);//前一個(gè)參數(shù)表示的是為那個(gè)對(duì)象賦密碼。
?????? System.out.println(user2.getPassword());
??? }
?
}
?
?
l?通過(guò)Field類訪問(wèn)對(duì)象屬性時(shí),需要注意訪問(wèn)權(quán)限的問(wèn)題,若對(duì)象
??? 的屬性被聲明為私有,則無(wú)法訪問(wèn),此時(shí)需要打開(kāi)java語(yǔ)言檢查
??? filed.setAccessible(true);
?
?
?
l?Method類代表某個(gè)類中的一個(gè)成員方法
l?通過(guò)invoke方法可以調(diào)用Method表示的方法,此時(shí)同樣需要傳遞
??? 對(duì)象給Method,若被調(diào)用的方法為靜態(tài),則傳入一個(gè)null值
l?注意:jdk1.4和jdk1.5的invoke方法的區(qū)別:
l?Jdk1.5:public Object invoke(Objectobj,Object... args)
l?Jdk1.4:public Object invoke(Objectobj,Object[] args)
l?當(dāng)傳入一個(gè)數(shù)組時(shí),為了向后兼容,虛擬機(jī)會(huì)優(yōu)先考慮考慮
??? 調(diào)用JDK1.4的方法
?
?
?
總結(jié)
以上是生活随笔為你收集整理的Java中的反射的应用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 吉利缤瑞在驻停等待怎么不显示p字了
- 下一篇: 最全的IO操作知识总结