小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Java高新技術-反射

 londonKu 2013-01-07

java的反射技術,其具體用途就是框架,不過作為初學者,對于框架是什么還很模糊,所以對于反射的理解有不夠深入。似乎很多編程模式都有用到反射的技術,不過對于什么是編程模式,我也只有一個很模糊的認識,買了一本java編程模式,發(fā)現(xiàn)根本看不懂。同樣吐槽一下《人月神話》,表示沒到一定的階段,這種書完全是天書。

好了,下面開始總結(jié)一下自己所學的:

一、反射的基礎是類,也就是Class.class,里面有很多方法,有些方法可以獲得內(nèi)存中的字節(jié)碼文件。而從這個字節(jié)碼文件又可以獲得對應類的構(gòu)造方法、成員變量、成員方法、內(nèi)部類。

先說一下拿到字節(jié)碼文件的3種方法:

String obja = "abc";
Class clazz1 = obja.getClass();
Class clazz2 = Class.forName("java.lang.String");
Class clazz3 = String.class;

以上3個Class對象指向的是同一份字節(jié)碼文件,所以三者是相等的。
拿到了Class對象,就可以調(diào)用一些方法獲得其構(gòu)造方法、成員變量、成員方法、內(nèi)部類。

構(gòu)造方法:

復制代碼
 Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 
          返回一個 Constructor 對象,該對象反映此 Class 對象所表示的類或接口的指定構(gòu)造方法。 
 Constructor<?>[] getDeclaredConstructors() 
          返回 Constructor 對象的一個數(shù)組,這些對象反映此 Class 對象表示的類聲明的所有構(gòu)造方法。 
 Constructor<T> getConstructor(Class<?>... parameterTypes) 
          返回一個 Constructor 對象,它反映此 Class 對象所表示的類的指定公共構(gòu)造方法。 
 Constructor<?>[] getConstructors() 
          返回一個包含某些 Constructor 對象的數(shù)組,這些對象反映此 Class 對象所表示的類的所有公共構(gòu)造方法。 
復制代碼

成員變量

復制代碼
 Field getDeclaredField(String name) 
          返回一個 Field 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明字段。 
 Field[] getDeclaredFields() 
          返回 Field 對象的一個數(shù)組,這些對象反映此 Class 對象所表示的類或接口所聲明的所有字段。 
 Field getField(String name) 
          返回一個 Field 對象,它反映此 Class 對象所表示的類或接口的指定公共成員字段。 
 Field[] getFields() 
          返回一個包含某些 Field 對象的數(shù)組,這些對象反映此 Class 對象所表示的類或接口的所有可訪問公共字段。 
復制代碼

成員方法

復制代碼
 Method getDeclaredMethod(String name, Class<?>... parameterTypes) 
          返回一個 Method 對象,該對象反映此 Class 對象所表示的類或接口的指定已聲明方法。 
 Method[] getDeclaredMethods() 
          返回 Method 對象的一個數(shù)組,這些對象反映此 Class 對象表示的類或接口聲明的所有方法,包括公共、保護、默認(包)訪問和私有方法,但不包括繼承的方法。 
 Method getMethod(String name, Class<?>... parameterTypes) 
          返回一個 Method 對象,它反映此 Class 對象所表示的類或接口的指定公共成員方法。 
 Method[] getMethods() 
          返回一個包含某些 Method 對象的數(shù)組,這些對象反映此 Class 對象所表示的類或接口(包括那些由該類或接口聲明的以及從超類和超接口繼承的那些的類或接口)的公共 member 方法。 
復制代碼

雖然看起來方法很多,可是只要記住以下幾點即可:
Method表示方法,F(xiàn)ield表示成員變量,Constructor表示構(gòu)造方法;后面加s表示一次獲取多個。
因為類中的成員如果public修飾符,外部不能直接訪問,所以有Declared的方法是可以獲取到public和非public的成員的。如果沒有Declared則表明獲取public的。
因為java中允許有多個同名的方法(普通方法和構(gòu)造方法),只要其傳入?yún)?shù)的類型(包括)不同即可,所以在獲取單個方法的時候,不光要指定方法的名稱,還要指定參數(shù)的類型。

以下方法估計用的較少,就不額為寫內(nèi)容了。
內(nèi)部類:(成員內(nèi)部類)

 Class<?>[] getDeclaredClasses() 
          返回 Class 對象的一個數(shù)組,這些對象反映聲明為此 Class 對象所表示的類的成員的所有類和接口。 
 Class<?> getDeclaringClass() 
          如果此 Class 對象所表示的類或接口是另一個類的成員,則返回的 Class 對象表示該對象的聲明類。 
 Class<?>[] getClasses() 
          返回一個包含某些 Class 對象的數(shù)組,這些對象表示屬于此 Class 對象所表示的類的成員的所有公共類和接口。 

注解

 <A extends Annotation> A getAnnotation(Class<A> annotationClass) 
          如果存在該元素的指定類型的注釋,則返回這些注釋,否則返回 null。 
 Annotation[] getAnnotations() 
          返回此元素上存在的所有注釋。 
 Annotation[] getDeclaredAnnotations() 
          返回直接存在于此元素上的所有注釋。 

判定

復制代碼
 boolean isAnnotation() 
          如果此 Class 對象表示一個注釋類型則返回 true。 
 boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 
          如果指定類型的注釋存在于此元素上,則返回 true,否則返回 false。 
 boolean isAnonymousClass() 
          當且僅當?shù)讓宇愂悄涿悤r返回 true。 
 boolean isArray() 
          判定此 Class 對象是否表示一個數(shù)組類。 
 boolean isAssignableFrom(Class<?> cls) 
          判定此 Class 對象所表示的類或接口與指定的 Class 參數(shù)所表示的類或接口是否相同,或是否是其超類或超接口。 
 boolean isEnum() 
          當且僅當該類聲明為源代碼中的枚舉時返回 true。 
 boolean isInstance(Object obj) 
          判定指定的 Object 是否與此 Class 所表示的對象賦值兼容。 
 boolean isInterface() 
          判定指定的 Class 對象是否表示一個接口類型。 
 boolean isLocalClass() 
          當且僅當?shù)讓宇愂潜镜仡悤r返回 true。 
 boolean isMemberClass() 
          當且僅當?shù)讓宇愂浅蓡T類時返回 true。 
 boolean isPrimitive() 
          判定指定的 Class 對象是否表示一個基本類型。 
 boolean isSynthetic() 
          如果此類是復合類,則返回 true,否則 false。 
復制代碼

一些復雜的方法

復制代碼
 Constructor<?> getEnclosingConstructor() 
          如果該 Class 對象表示構(gòu)造方法中的一個本地或匿名類,則返回 Constructor 對象,它表示底層類的立即封閉構(gòu)造方法。 
 Method getEnclosingMethod() 
          如果此 Class 對象表示某一方法中的一個本地或匿名類,則返回 Method 對象,它表示底層類的立即封閉方法。 
<U> Class<? extends U>  asSubclass(Class<U> clazz) 
          強制轉(zhuǎn)換該 Class 對象,以表示指定的 class 對象所表示的類的一個子類。 
 T cast(Object obj) 
          將一個對象強制轉(zhuǎn)換成此 Class 對象所表示的類或接口。 
 boolean desiredAssertionStatus() 
          如果要在調(diào)用此方法時將要初始化該類,則返回將分配給該類的斷言狀態(tài)。 
 String getCanonicalName() 
          返回 Java Language Specification 中所定義的底層類的規(guī)范化名稱。 
 Class<?> getComponentType() 
          返回表示數(shù)組組件類型的 Class。 
 Class<?> getEnclosingClass() 
          返回底層類的立即封閉類。 
 T[] getEnumConstants() 
          如果此 Class 對象不表示枚舉類型,則返回枚舉類的元素或 null。 
 Type[] getGenericInterfaces() 
          返回表示某些接口的 Type,這些接口由此對象所表示的類或接口直接實現(xiàn)。 
 Type getGenericSuperclass() 
          返回表示此 Class 所表示的實體(類、接口、基本類型或 void)的直接超類的 Type。 
 Class<?>[] getInterfaces() 
          確定此對象所表示的類或接口實現(xiàn)的接口。 
 ProtectionDomain getProtectionDomain() 
          返回該類的 ProtectionDomain。 
 URL getResource(String name) 
          查找?guī)в薪o定名稱的資源。 
 InputStream getResourceAsStream(String name) 
          查找具有給定名稱的資源。 
 Object[] getSigners() 
          獲取此類的標記。 
 Class<? super T> getSuperclass() 
          返回表示此 Class 所表示的實體(類、接口、基本類型或 void)的超類的 Class。 
 TypeVariable<Class<T>>[] getTypeParameters() 
          按聲明順序返回 TypeVariable 對象的一個數(shù)組,這些對象表示用此 GenericDeclaration 對象所表示的常規(guī)聲明來聲明的類型變量。 
復制代碼

幾個比較簡單的方法:

復制代碼
 int getModifiers() 
          返回此類或接口以整數(shù)編碼的 Java 語言修飾符。 //參見java.lang.reflect.Modifier
 Package getPackage() 
          獲取此類的包。 //簡單
 ClassLoader getClassLoader() 
          返回該類的類加載器。 //后面的類加載器和講代理的時候要用。
 T newInstance() 
          創(chuàng)建此 Class 對象所表示的類的一個新實例。 //用該類的空參數(shù)的構(gòu)造方法。
復制代碼

二、自己研究反射方法的一些代碼:

復制代碼
import java.lang.reflect.*;
import java.util.Arrays;
public class ReflectMethod {

    public static void main(String[] args) throws Exception {
        String obja = "abc";
        Class clazz1 = obja.getClass();
        Class clazz2 = Class.forName("java.lang.String");
        Class clazz3 = String.class;
        //證明是同一份字節(jié)碼
        System.out.println(clazz1==clazz2);
        System.out.println(clazz1==clazz3);
        
        //想了解一下String.class中有哪些方法。
        int publicMethodsInString = 0;
        int otherMethodsInString = 0;
        int allMethodsInString = 0;
        //用增強for循環(huán)獲取public方法
        for (Method c : clazz1.getMethods()  ){
            //打印各種方法。
            //System.out.println(c);
            publicMethodsInString++;
        }
        System.out.println("----------------------");
        //獲取Declared方法。
        for (Method c : clazz1.getDeclaredMethods() ){
            //打印各種方法,包括私有,但打印后發(fā)現(xiàn)前者并不是后者的子集,發(fā)現(xiàn)此方法不會返回此類從父類繼承的方法
            //System.out.println(c);
            otherMethodsInString++;
        }
        System.out.println("----------------------");
        //自己定義了一個靜態(tài)方法,嘗試獲取類中所有的方法。
        for (Method c : allMethods(clazz1) ){
            //打印所有方法
            //System.out.println(c);
            allMethodsInString++;
        }
        //從下列語句看看獲取的方法的數(shù)量
        System.out.println("publicMethods:" + publicMethodsInString + "  otherMethodsAtString:"+ otherMethodsInString +"  AllMethods:"+ allMethodsInString);
        System.out.println("+++++++++++++++++++++");
        for (Method c : allMethods(clazz1) ){
            //打印所有方法
            if (!Modifier.isPublic(c.getModifiers()))
                System.out.println(c);
            //79 -72 == 7 也打印了7條語句,說明是正確的。
        }
        System.out.println("");
        //來嘗試一下理由反射使用String類中的非public方法??戳艘幌?,決定嘗試hash32這個方法(其他的參數(shù)太多,而且不懂是什么意思)。
        //第一遍寫成了 clazz1.getMethod("hash32")拋出沒有這個方法的異常;
        Method hash32Method = clazz1.getDeclaredMethod("hash32");
        //要暴力反射
        hash32Method.setAccessible(true);
        //每次打印結(jié)果都不一樣,還真猜不出來這個是做什么的。就不去看源代碼了。
        System.out.println(hash32Method.invoke("abc"));
    }
    //返回一個類的所有的方法的自定義方法。感覺過程略顯羅嗦。
    public static Method[] allMethods(Class cla){
        int pubLength =  cla.getMethods().length;
        int otherLength = 0;
        Method[] pubM = cla.getMethods();
        Method[] otherM = cla.getDeclaredMethods();
        for (int x = 0 ; x < otherM.length; x++){
            if (!Modifier.isPublic(otherM[x].getModifiers())){
                otherLength++;
            }
        }
        int allLength = otherLength + pubLength;
        Method[] allM = new Method[allLength];
        for (int x = 0 ; x < pubLength; x++){
            allM[x] = pubM[x];
        }
        for (int x = 0 ,y =0; x < otherM.length; x++){
            if (!Modifier.isPublic(otherM[x].getModifiers())){
                allM[y + pubLength] = otherM[x];
                y++;
            }
        }
        return allM;
    }
}
復制代碼

三、反射成員變量的代碼:

復制代碼
import java.io.*;
import java.lang.reflect.*;
public class ReflectField {
    //本來想在java中自帶的類中找一個類做成員變量的反射的。結(jié)果發(fā)現(xiàn),成員變量要么很麻煩,
    public static void main(String[] args) throws Exception {
        //在D盤上建了一個new.txt,里面的內(nèi)容為:單行小寫,雙行大寫:如
        //abcdefghijklmnopqrstuvwxyz0123456789
        //ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789
        BufferedInputStream bufr = new BufferedInputStream(new FileInputStream("d:/new.txt"));
        Class clazz = bufr.getClass();
        //getFields()沒有結(jié)果,試試getDeclaredFields()
        for (Field f : clazz.getDeclaredFields()){
            f.setAccessible(true);
            //System.out.println(f);
        }
        //需要暴力反射才行
        /*
        Field posField = clazz.getDeclaredField("pos");
        posField.setAccessible(true);
        //初始pos在0上,read一次之后,pos到了1.
        System.out.println(posField.get(bufr));
        System.out.println(bufr.read());
        System.out.println(posField.get(bufr));
        */
        //上面太麻煩了。我想了解一下所有的成員變量的變化情況
        for (Field f : clazz.getDeclaredFields()){
            f.setAccessible(true);
            System.out.println(f.getName()+":  "+f.get(bufr));
        }
        bufr.read();
        for (Field f : clazz.getDeclaredFields()){
            f.setAccessible(true);
            System.out.println(f.getName()+":  "+f.get(bufr));
        }
        //從運行結(jié)果可以看出一些BufferedInputStream的運作原理:
        //默認的buf是8k的。
        //在第一次read的時候,才會去硬盤讀取文件。因為read前,count為0,read后,count為378(我的文件共10行,每行38個byte,26個字母、10個數(shù)字、換行符、回車符,而且我最后一行沒有換行)
        //猜測count是文件的大小。為例進一步研究,必須找一個大于8k的文件,我從系統(tǒng)目錄下復制了Explorer.exe作為實驗載體。
        bufr.close();
        
        BufferedInputStream bufr2 = new BufferedInputStream(new FileInputStream("d:/explorer.exe"));
        for (Field f : clazz.getDeclaredFields()){
            f.setAccessible(true);
            System.out.println(f.getName()+":  "+f.get(bufr2));
        }
        //x< 1;x< 100;x< 8192;x< 8193;x< 10000;表示分別讀x次。
        for(int x = 0;x <10000;x++)
            bufr2.read();
        for (Field f : clazz.getDeclaredFields()){
            f.setAccessible(true);
            System.out.println(f.getName()+":  "+f.get(bufr2));
        }
        bufr.close();
        //查看打印結(jié)果后發(fā)現(xiàn),count其實不是文件大小。為了搞清楚。必須多read幾次。研究后發(fā)現(xiàn)只有pos在變化count其實=bufr2.read(buf);
        //還是嘗試更改pos的值試試。
        BufferedInputStream bufr3 = new BufferedInputStream(new FileInputStream("d:/new.txt"));
        Class clazz3 = bufr3.getClass();        
        Field posField2 = clazz3.getDeclaredField("pos");
        posField2.setAccessible(true);
        System.out.println(bufr3.read());//97
        posField2.get(bufr3);
        System.out.println(bufr3.read());//98
        posField2.get(bufr3);
        //更改pos的值為0,看read的結(jié)果
        posField2.set(bufr3,0);
        System.out.println(bufr3.read());//97,證實pos和和read方法有關系
        bufr3.close();
    }
}
復制代碼

四、反射構(gòu)造方法的代碼(簡單的):

復制代碼
import java.lang.reflect.*;
public class ReflectConstrator {
    //Sting.class的構(gòu)造方法比較多,我們來看一下
    public static void main(String[] args) throws Exception {
        Class clazz = String.class;
        //getDeclaredConstructors()發(fā)現(xiàn)Constructors()比多2個構(gòu)造方法。
        //java.lang.String(int,int,char[])
        //java.lang.String(char[],boolean)
        Constructor[] cons = clazz.getDeclaredConstructors();
        for (Constructor con: cons){
            System.out.println(con);
        }
        //試試這兩個方法
        char[] chs = {'a','b','c','w','x','y','z','9'};
        Constructor con1 =clazz.getDeclaredConstructor(int.class,int.class,char[].class);
        con1.setAccessible(true);
        String str1 = (String) con1.newInstance(2,5,chs);
        System.out.println(str1);
        //發(fā)現(xiàn)此構(gòu)造方法的使用應該和public java.lang.String(char[],int,int)一致,只是參數(shù)順序不同。所以沒有必要對外提供。
        /*Constructor con3 =clazz.getDeclaredConstructor(char[].class,int.class,int.class);
        con3.setAccessible(true);
        String str3 = (String) con3.newInstance(chs,2,5);
        System.out.println(str3);*/
        //試一下第二種構(gòu)造方法,
        Constructor con2 =clazz.getDeclaredConstructor(char[].class,boolean.class);
        con2.setAccessible(true);
        String str2 = (String)con2.newInstance(chs, true);
        System.out.println(str2);
        String str4 = (String)con2.newInstance(chs, false);
        System.out.println(str4);
        //第二個參數(shù)設置為true和false打印結(jié)果居然一致,奇怪。那么其用法英格和public java.lang.String(char[])一致。
        Constructor con4 =clazz.getDeclaredConstructor(char[].class);
        String str6 = (String)con4.newInstance(chs);
        System.out.println(str6);
        //的確如此
    }
}
復制代碼

五、總結(jié)

反射的基礎應用還是很簡單的。尤其Constructor Field Method這3個類中的方法,看一下api文檔就知道是干什么的了。

但是高級應用,就比較復雜了,需要多學習幾遍張老師的視頻,雖然張老師講得不是特別適合初學者,不過多聽幾遍應該能懂。

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多