java反射實例解析
Class類的構(gòu)造方法是private,由JVM創(chuàng)建。
反射是java語言的一個特性,它允程序在運(yùn)行時(注意不是編譯的時候)來進(jìn)行自我檢查并且對內(nèi)部的成員進(jìn)行操作。例如它允許一個java的類獲取他所有的成員變量和方法并且顯示出來。Java 的這一能力在實際應(yīng)用中也許用得不是很多,但是在其它的程序設(shè)計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程序中獲得函數(shù)定義相關(guān)的信息。 (來自Sun)
JavaBean 是 reflection 的實際應(yīng)用之一,它能讓一些工具可視化的操作軟件組件。這些工具通過 reflection 動態(tài)的載入并取得 Java 組件(類) 的屬性。
反射是從1.2就有的,后面的三大框架都會用到反射機(jī)制,涉及到類”Class”,無法直接new CLass(),其對象是內(nèi)存里的一份字節(jié)碼。
Class 類的實例表示正在運(yùn)行的 Java 應(yīng)用程序中的類和接口。枚舉是一種類,注釋是一種接口。每個數(shù)組屬于被映射為 Class 對象的一個類,所有具有相同元素類型和維數(shù)的數(shù)組都共享該 Class 對象?;镜?Java類型(boolean、byte、char、short、int、long、float 和 double)和關(guān)鍵字 void 也表示為 Class 對象。Class 沒有公共構(gòu)造方法。Class 對象是在加載類時由 Java 虛擬機(jī)以及通過調(diào)用類加載器中的 defineClass 方法自動構(gòu)造的。
1Person p1 = newPerson(); 2//下面的這三種方式都可以得到字節(jié)碼3CLass c1 =Date.class(); 4p1.getClass(); 5//若存在則加載,否則新建,往往使用第三種,類的名字在寫源程序時不需要知道,到運(yùn)行時再傳遞過來6Class.forName( “java.lang.String”);
CLass.forName()字節(jié)碼已經(jīng)加載到j(luò)ava虛擬機(jī)中,去得到字節(jié)碼;java虛擬機(jī)中還沒有生成字節(jié)碼 用類加載器進(jìn)行加載,加載的字節(jié)碼緩沖到虛擬機(jī)中。
考慮下面這個簡單的例子,讓我們看看 reflection 是如何工作的。
import java.lang.reflect.*; publicclassDumpMethods { publicstaticvoidmain(String args[]) {try{ Class c = Class.forName( “java.util.Stack”); Method m[] = c.getDeclaredMethods();for( inti = 0; i 《 m.length; i++) System. out.println(m[i].toString()); } catch(Throwable e){ System.err.println(e); } } } 1public synchronized java .lang.Objectjava .util.Stack.pop()2public java .lang.Objectjava .util.Stack.push(java .lang.Object) 3public boolean java.util.Stack.empty() 4public synchronized java .lang.Objectjava .util.Stack.peek() 5public synchronized int java .util.Stack.search(java .lang.Object)
這樣就列出了java.util.Stack 類的各方法名以及它們的限制符和返回類型。這個程序使用 Class.forName 載入指定的類,然后調(diào)用 getDeclaredMethods 來獲取這個類中定義了的方法列表。java.lang.reflect.Methods 是用來描述某個類中單個方法的一個類。
以下示例使用 Class 對象來顯示對象的類名:
1void printClassName(Object obj) { 2System .out.println( “The class of ”+ obj + 3“ is ”+ obj.getClass() .getName()) ;4}
還可以使用一個類字面值(JLS Section 15.8.2)來獲取指定類型(或 void)的 Class 對象。例如:
1System .out.println( “The name of class Foo is: ”+Foo .class.getName()) ;
在沒有對象實例的時候,主要有兩種辦法。
//獲得類類型的兩種方式 Class cls1 = Role. class; Class cls2 = Class.forName( “yui.Role”);
注意第二種方式中,forName中的參數(shù)一定是完整的類名(包名+類名),并且這個方法需要捕獲異?!,F(xiàn)在得到cls1就可以創(chuàng)建一個Role類的實例了,利用Class的newInstance方法相當(dāng)于調(diào)用類的默認(rèn)的構(gòu)造器。
1Objecto = cls1.newInstance(); 2//創(chuàng)建一個實例 3//Object o1 = new Role(); //與上面的方法等價二。常用方法
1.isPrimitive(判斷是否是基本類型的字節(jié)碼)
publicclassTestReflect { publicstaticvoidmain(String[] args) { // TODO Auto-generated method stubString str = “abc”; Class cls1 = str.getClass(); Class cls2 = String. class; Class cls3 = null; //必須要加上nulltry{ cls3 = Class.forName( “java.lang.String”); }catch(ClassNotFoundException e) { // TODO Auto-generated catch blocke.printStackTrace(); } System. out.println(cls1==cls2); System.out.println(cls1==cls3); System. out.println(cls1.isPrimitive()); System. out.println( int.class.isPrimitive()); //判定指定的 Class 對象是否表示一個基本類型。System. out.println(int. class== Integer. class); System. out.println( int. class== Integer.TYPE); System.out.println( int[]。 class.isPrimitive()); System. out.println( int[]。 class.isArray()); } } /* * true true false true false true false true */*/
2.getConstructor和getConstructors()
java中構(gòu)造方法沒有先后順序,通過類型和參數(shù)個數(shù)區(qū)分。
/** * Java學(xué)習(xí)交流QQ群:589809992 我們一起學(xué)Java! */publicclassTestReflect{publicstaticvoidmain(String[] args) throwsSecurityException, NoSuchMethodException { // TODO Auto-generated method stubString str = “abc”; System.out.println(String.class.getConstructor(StringBuffer.class)); } }
3.Filed類代表某一類中的一個成員變量。
import java.lang.reflect.Field; publicclassTestReflect { publicstaticvoidmain(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception { ReflectPointer rp1 = newReflectPointer( 3, 4); Field fieldx = rp1.getClass().getField( “x”); //必須是x或者ySystem. out.println(fieldx. get(rp1)); /* * private的成員變量必須使用getDeclaredField,并setAccessible(true),否則看得到拿不到 */Field fieldy = rp1.getClass().getDeclaredField( “y”); fieldy.setAccessible( true); //暴力反射System. out.println(fieldy. get(rp1)); } } class ReflectPointer { publicintx = 0; privateinty =0; publicReflectPointer( intx, inty) { //alt + shift +s相當(dāng)于右鍵sourcesuper(); // TODO Auto-generated constructor stubthis.x = x; this.y = y; } }三。典型例題
1.將所有String類型的成員變量里的b改成a。
importjava.lang.reflect.Field; publicclassTestReflect{publicstaticvoidmain(String[] args)throwsSecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception { ReflectPointer rp1 = newReflectPointer( 3, 4); changeBtoA(rp1); System.out.println(rp1); } privatestaticvoidchangeBtoA(Object obj)throwsRuntimeException, Exception { Field[] fields = obj.getClass().getFields(); for(Field field : fields) { //if(field.getType().equals(String.class))//由于字節(jié)碼只有一份,用equals語義不準(zhǔn)確if(field.getType()==String.class) { String oldValue = (String)field.get(obj); String newValue = oldValue.replace( ‘b’, ‘a(chǎn)’); field.set(obj,newValue); } } } } class ReflectPointer {privateintx = 0; publicinty = 0; publicString str1 = “ball”; publicString str2 = “basketball”;publicString str3 = “itcat”; publicReflectPointer( intx, inty) { //alt + shift +s相當(dāng)于右鍵sourcesuper(); // TODO Auto-generated constructor stubthis.x = x; this.y = y; }@OverridepublicString toString() { return“ReflectPointer [str1=”+ str1 + “, str2=”+ str2 + “, str3=”+ str3 + “]”; } }
2.寫一個程序根據(jù)用戶提供的類名,調(diào)用該類的里的main方法。
為什么要用反射的方式呢?
importjava.lang.reflect.Field; importjava.lang.reflect.Method; /** * Java學(xué)習(xí)交流QQ群:589809992 我們一起學(xué)Java! */publicclassTestReflect{publicstaticvoidmain(String[] args)throwsSecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception { String str = args[ 0]; /* * 這樣會數(shù)組角標(biāo)越界,因為壓根沒有這個字符數(shù)組 * 需要右鍵在run as-configurations-arguments里輸入b.Inter(完整類名) * */Method m = Class.forName(str).getMethod( “main”,String[].class); //下面這兩種方式都可以,main方法需要一個參數(shù)m.invoke( null, newObject[]{ newString[]{ “111”, “222”,“333”}}); m.invoke( null, (Object) newString[]{ “111”, “222”, “333”}); //這個可以說明,數(shù)組也是Object/* * m.invoke(null, new String[]{“111”,“222”,“333”}) * 上面的不可以,因為java會自動拆包 */} } class Inter { publicstaticvoidmain(String[] args) { for(Object obj : args) { System.out.println(obj); } } }
3.模擬 instanceof 操作符
class S { } publicclassIsInstance { publicstaticvoidmain(String args[]) { try{ Class cls = Class.forName( “S”); boolean b1 = cls.isInstance( newInteger( 37)); System.out.println(b1); boolean b2 = cls.isInstance( newS()); System. out.println(b2); }catch(Throwable e) { System.err.println(e); } } }
在這個例子中創(chuàng)建了一個S 類的 Class 對象,然后檢查一些對象是否是S的實例。Integer(37) 不是,但 new S()是。
四.Method類
代表類(不是對象)中的某一方法。
import java.lang.reflect.Field; import java.lang.reflect.Method; /* * 人在黑板上畫圓,涉及三個對象,畫圓需要圓心和半徑,但是是私有的,畫圓的方法 * 分配給人不合適。Java學(xué)習(xí)交流QQ群:589809992 我們一起學(xué)Java! * * 司機(jī)踩剎車,司機(jī)只是給列車發(fā)出指令,剎車的動作還需要列車去完成。 * * 面試經(jīng)常考面向?qū)ο蟮脑O(shè)計,比如人關(guān)門,人只是去推門。 * * 這就是專家模式:誰擁有數(shù)據(jù),誰就是專家,方法就分配給誰 */publicclassTestReflect {publicstaticvoidmain(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception { String str = “shfsfs”; //包開頭是com表示是sun內(nèi)部用的,java打頭的才是用戶的Method mtCharAt = String.class.getMethod( “charAt”, int.class); Object ch = mtCharAt.invoke(str, 1); //若第一個參數(shù)是null,則肯定是靜態(tài)方法System. out.println(ch); System.out.println(mtCharAt.invoke(str, newObject[]{ 2})); //1.4語法} }五。數(shù)組的反射
Array工具類用于完成數(shù)組的反射操作。
同類型同緯度有相同的字節(jié)碼。
int.class和Integer.class不是同一份字節(jié)碼,Integer.TYPE,TYPE代表包裝類對應(yīng)的基本類的字節(jié)碼 int.class==Integer.TYPE
import java.util.Arrays; /* * 從這個例子看出即便字節(jié)碼相同但是對象也不一定相同,根本不是一回事 * */publicclassTestReflect { publicstaticvoidmain(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception { int[] a = newint[ 3]; int[] b = newint[]{ 4, 5, 5}; //直接賦值后不可以指定長度,否則CEint[][] c = newint[ 3][ 2]; String[] d = newString[]{ “jjj”,“kkkk”}; System. out.println(a==b); //falseSystem. out.println(a.getClass()==b.getClass());//true//System.out.println(a.getClass()==d.getClass()); //比較字節(jié)碼a和cd也沒法比System.out.println(a.getClass()); //輸出class [ISystem. out.println(a.getClass().getName()); //輸出[I,中括號表示數(shù)組,I表示整數(shù)System. out.println(a.getClass().getSuperclass()); //輸出class java.lang.ObjectSystem. out.println(d.getClass().getSuperclass()); //輸出class java.lang.Object//由于父類都是Object,下面都是可以的Object obj1 = a; //不可是Object[]Object obj2 = b; Object[] obj3 = c; //基本類型的一位數(shù)組只可以當(dāng)做Object,非得還可以當(dāng)做Object[]Object obj4 = d; //注意asList處理int[]和String[]的區(qū)別System.out.println(Arrays.asList(b)); //1.4沒有可變參數(shù),使用的是數(shù)組,[[I@1bc4459]System.out.println(Arrays.asList(d)); //[jjj, kkkk]} }六。結(jié)束語 以上就是反射機(jī)制的簡單的使用,顯然學(xué)過spring的朋友一定明白了,為什么可以通過配置文件就可以讓我們獲得指定的方法和變量,在我們創(chuàng)建對象的時候都是通過傳進(jìn)string實現(xiàn)的,就好像你需要什么,我們?nèi)槟闵a(chǎn),還有我們一直在用Object,這就說明java語言的動態(tài)特性,依賴性大大的降低了。
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%