1. 程式人生 > >java內功系列五(類載入與反射)

java內功系列五(類載入與反射)

1.java程式啟動時啟動了一個jvm的虛擬機器程序,所有執行緒變數都在該虛擬機器中。
2.當程式使用某個類時發現沒有那麼會從檔案中載入到記憶體中,並建立一個java.lang.class物件。(載入、連結、初始化),類時對事物的抽象,其實類本身也是一種事物,對它的抽閒就是java.lang.class,所以系統中的所有類其實也是例項(java.lang.class例項)。
3.類載入器有根載入器(jvm提供)和其它載入器(java語言編寫:本地載入,jar載入,網路載入,其它載入),可以自己繼承classloader實現自己的類載入器。jvm允許預先載入某些類。
4.classloaer只是把二進位制檔案載入但是不會初始化,當使用class.forname方法才會初始化。(對於finnal物件如果在編譯時已經能確定值那麼在編譯的時候會替換成具體的值)
5.類載入器:根載入器(載入java核心類,string,int等)、擴充套件載入器(一般載入%javahome%jre/lib/ext下的jar)、系統載入器(我們自己寫的程式檔案)、使用者載入器(自定義的載入器),一個類被2中不同的載入器載入那麼他們在jvm中是不一樣的。

6.java執行大部分物件會出現2中型別:編譯時型別和執行時型別。(person p=new student;)編譯時person,執行時student。
7.獲取類有class.forname(class.forname("全名"))、類.class(person.class)、物件.getclass(pers.getclass())。
8.class物件可以獲得對應類的建構函式、方法、屬性、annotation、內部類、外部類、實現介面、父類、修飾符、所在包、類名等基本資訊。並提供了判斷該class物件對應的類是否為介面、列舉註解等。
9.反射用class物件的newinstance方法建立例項(spring就是使用配置檔案生成具體的類)、也可用class物件獲取對應類的建構函式後建立物件。
10.class物件可以獲取對應物件的方法method物件,然後呼叫method物件的invoke方法呼叫例項物件方法,spring使用該方法給物件的欄位或者依賴物件賦值(setter方法)。這也是ioc的核心思想。
10.class物件可以獲取對應類的成員變數,並且可以對變數進行賦值或讀取。
11.陣列也可以實現反射建立、獲取、設定。
12.使用proxy和invocationHander建立動態代理物件。
 Proxy.getProxyClass(arg0, arg1) 建立動態代理類
 Proxy.newProxyInstance(loader, interfaces, h) 建立動態代理物件(使用多),代理物件的執行最後都是呼叫h物件的invoke執行的。
13.aop實現的原理就是使用proxy和invocationHander建立動態代理。首先實現invocationHander介面,在invocationHander實習類中保留一個真正被代理物件,在invocationHander中只有一個invoke方法,這樣需要在方法呼叫前後做必要的處理(驗證、日誌等或者直接不讓函式執行返回空),proxy負責根據介面生成代理物件框架,代理物件內部呼叫全部使用invocationHander實現類物件的invoke方法,只是每個方法傳遞的引數不一樣(method方法和引數),這樣就可以根據反射呼叫真正被代理物件的方法(method.invoke(真正物件,引數))。這樣就實現了在一個地方(invocationHander實現類的invoke方法中)集中的編寫橫切面邏輯(日誌、驗證等)讓所有的方法都可以應用到。
14.java的class類增加了泛型功能,例如:string.class實際上就是class<Sring>,如果class對應的型別未知可以使用class<?>。使用泛型可以解決反射中型別的強制轉換。
15.反射可以獲取到一個類的欄位型別,但是這個欄位型別只能是非泛型化的(int,對應欄位型別是map<string,int>這種不行),如果泛型化的需要得到型別後進行轉換。
    public class generictest
    {
        private Map<String, Integer> score;
        public static void main(String[] args) throws Exception
        {
            Class<generictest> clazz=generictest.class;
            Field f=clazz.getDeclaredField("score");
            //直接使用gettype取出型別
            Class<?> a=f.getType();
            System.out.println(a);//只能輸出java.util.Map
            Type gtype=f.getGenericType();
            if(gtype instanceof ParameterizedType)
            {
                ParameterizedType ptype=(ParameterizedType)gtype;
                //返回原始型別和上面那個一樣
                Type rtype=ptype.getRawType();
                System.out.println(rtype);
                Type[] targs=ptype.getActualTypeArguments();
                for(int i=0;i<targs.length;i++)
                {
                    System.out.println(targs[i]);//這將輸出string和Integer
                }
            }
            else
            {
                System.out.println("出錯");
            }    
            
        }
    }