java反射實例解析
Class類的構造方法是private,由JVM創建。
反射是java語言的一個特性,它允程序在運行時(注意不是編譯的時候)來進行自我檢查并且對內部的成員進行操作。例如它允許一個java的類獲取他所有的成員變量和方法并且顯示出來。Java 的這一能力在實際應用中也許用得不是很多,但是在其它的程序設計語言中根本就不存在這一特性。例如,Pascal、C 或者 C++ 中就沒有辦法在程序中獲得函數定義相關的信息。 (來自Sun)
JavaBean 是 reflection 的實際應用之一,它能讓一些工具可視化的操作軟件組件。這些工具通過 reflection 動態的載入并取得 Java 組件(類) 的屬性。
反射是從1.2就有的,后面的三大框架都會用到反射機制,涉及到類”Class”,無法直接new CLass(),其對象是內存里的一份字節碼。
Class 類的實例表示正在運行的 Java 應用程序中的類和接口。枚舉是一種類,注釋是一種接口。每個數組屬于被映射為 Class 對象的一個類,所有具有相同元素類型和維數的數組都共享該 Class 對象。基本的 Java類型(boolean、byte、char、short、int、long、float 和 double)和關鍵字 void 也表示為 Class 對象。Class 沒有公共構造方法。Class 對象是在加載類時由 Java 虛擬機以及通過調用類加載器中的 defineClass 方法自動構造的。
1Person p1 = newPerson(); 2//下面的這三種方式都可以得到字節碼3CLass c1 =Date.class(); 4p1.getClass(); 5//若存在則加載,否則新建,往往使用第三種,類的名字在寫源程序時不需要知道,到運行時再傳遞過來6Class.forName( “java.lang.String”);
CLass.forName()字節碼已經加載到java虛擬機中,去得到字節碼;java虛擬機中還沒有生成字節碼 用類加載器進行加載,加載的字節碼緩沖到虛擬機中。
考慮下面這個簡單的例子,讓我們看看 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 載入指定的類,然后調用 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中的參數一定是完整的類名(包名+類名),并且這個方法需要捕獲異常。現在得到cls1就可以創建一個Role類的實例了,利用Class的newInstance方法相當于調用類的默認的構造器。
1Objecto = cls1.newInstance(); 2//創建一個實例 3//Object o1 = new Role(); //與上面的方法等價二。常用方法
1.isPrimitive(判斷是否是基本類型的字節碼)
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中構造方法沒有先后順序,通過類型和參數個數區分。
/** * Java學習交流QQ群:589809992 我們一起學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相當于右鍵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))//由于字節碼只有一份,用equals語義不準確if(field.getType()==String.class) { String oldValue = (String)field.get(obj); String newValue = oldValue.replace( ‘b’, ‘a’); 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相當于右鍵sourcesuper(); // TODO Auto-generated constructor stubthis.x = x; this.y = y; }@OverridepublicString toString() { return“ReflectPointer [str1=”+ str1 + “, str2=”+ str2 + “, str3=”+ str3 + “]”; } }
2.寫一個程序根據用戶提供的類名,調用該類的里的main方法。
為什么要用反射的方式呢?
importjava.lang.reflect.Field; importjava.lang.reflect.Method; /** * Java學習交流QQ群:589809992 我們一起學Java! */publicclassTestReflect{publicstaticvoidmain(String[] args)throwsSecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception { String str = args[ 0]; /* * 這樣會數組角標越界,因為壓根沒有這個字符數組 * 需要右鍵在run as-configurations-arguments里輸入b.Inter(完整類名) * */Method m = Class.forName(str).getMethod( “main”,String[].class); //下面這兩種方式都可以,main方法需要一個參數m.invoke( null, newObject[]{ newString[]{ “111”, “222”,“333”}}); m.invoke( null, (Object) newString[]{ “111”, “222”, “333”}); //這個可以說明,數組也是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); } } }
在這個例子中創建了一個S 類的 Class 對象,然后檢查一些對象是否是S的實例。Integer(37) 不是,但 new S()是。
四.Method類
代表類(不是對象)中的某一方法。
import java.lang.reflect.Field; import java.lang.reflect.Method; /* * 人在黑板上畫圓,涉及三個對象,畫圓需要圓心和半徑,但是是私有的,畫圓的方法 * 分配給人不合適。Java學習交流QQ群:589809992 我們一起學Java! * * 司機踩剎車,司機只是給列車發出指令,剎車的動作還需要列車去完成。 * * 面試經常考面向對象的設計,比如人關門,人只是去推門。 * * 這就是專家模式:誰擁有數據,誰就是專家,方法就分配給誰 */publicclassTestReflect {publicstaticvoidmain(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception { String str = “shfsfs”; //包開頭是com表示是sun內部用的,java打頭的才是用戶的Method mtCharAt = String.class.getMethod( “charAt”, int.class); Object ch = mtCharAt.invoke(str, 1); //若第一個參數是null,則肯定是靜態方法System. out.println(ch); System.out.println(mtCharAt.invoke(str, newObject[]{ 2})); //1.4語法} }五。數組的反射
Array工具類用于完成數組的反射操作。
同類型同緯度有相同的字節碼。
int.class和Integer.class不是同一份字節碼,Integer.TYPE,TYPE代表包裝類對應的基本類的字節碼 int.class==Integer.TYPE
import java.util.Arrays; /* * 從這個例子看出即便字節碼相同但是對象也不一定相同,根本不是一回事 * */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()); //比較字節碼a和cd也沒法比System.out.println(a.getClass()); //輸出class [ISystem. out.println(a.getClass().getName()); //輸出[I,中括號表示數組,I表示整數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; //基本類型的一位數組只可以當做Object,非得還可以當做Object[]Object obj4 = d; //注意asList處理int[]和String[]的區別System.out.println(Arrays.asList(b)); //1.4沒有可變參數,使用的是數組,[[I@1bc4459]System.out.println(Arrays.asList(d)); //[jjj, kkkk]} }六。結束語 以上就是反射機制的簡單的使用,顯然學過spring的朋友一定明白了,為什么可以通過配置文件就可以讓我們獲得指定的方法和變量,在我們創建對象的時候都是通過傳進string實現的,就好像你需要什么,我們去為你生產,還有我們一直在用Object,這就說明java語言的動態特性,依賴性大大的降低了。
非常好我支持^.^
(0) 0%
不好我反對
(0) 0%