註解和反射

註解

作用:

         不是程序本身,可以對程序作出解釋;可以被其他程序讀取。

格式:

         註解時以"@註釋名"在代碼中存在的,還可以添加一些參數值;

位置:

         可以附加在package,class,method,field等上面,相當於給他們添加了額外的輔助信息,可以通過反射機制編程實現對這些數據的訪問。

常見內置註解:

     @Override:定義在java.lang.Override中,此註釋只適用於修辭方法,表示一個方法聲明打算重新超類中的一個方法聲明。
     @Deprecated:定義在java.lang.DePrecated中,此註釋可以用於修辭方法,屬性,類,表示不鼓勵程序員使用這樣的元素,通常是因爲它很危險或存在更好的選擇。
     @SuppressWarnings:定義在java.lang.SuppressWarnings中,用來抑制編譯時的警告信息。(需要添加一個定義好的參數才能使用)

元註解

作用:

       負責註解其他註解,java定義了4個標準的meta-annotation類型,被用來提供對其他註解類型作說明。

       @Target:用於描述註解的使用範圍(即:被描述的註解可以用在什麼地方)
       @Retention:表示需要在什麼級別保存該註解信息,用於描述註解的生命週期(SOURCE<CLASS<RUNTIME)
       @Document:說明該註解將被包含在javadoc中
       @Inherited:說明子類可以繼承父類中的該註解

自定義註解:

       使用@interface自定義註解時,自動繼承了java.lang.annotaion.Annotation接口

分析:

       @interface用來聲明一個註解,格式:@ interface 註解名{ 定義內容 }
       其中內容的每一個方法實際上是聲明瞭一個配置參數。
       方法的名稱就是參數的名稱。
       返回值類型就是參數的類型(返回值只能是基本類型,Class,String,enum)。
       可以通過default來聲明參數的默認值
       如果只有一個參數成員,一般參數名爲value
       註解元素必須要有值,我們定義註解元素時,經常使用空字符串,0作爲默認值。

動態語言

      是一類在運行時可以改變其結構的語言:例如新的函數、對象、甚至代碼可以被引進,已有的函數可以被刪除或是其他結構上的變化。通俗點說就是在運行時代碼可以根據某些條件改變自身結構。

靜態語言

      與動態語言相對應,運行時結構不可變的語言就是靜態語言。

反射

       JAVA反射機制實在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲java語言的反射機制。
       要想解剖一個類,必須先要獲取到該類的字節碼文件對象。而解剖使用的就是Class類中的方法,所以先要獲取到每一個字節碼文件對應的Class類型的對象。

反射:就是通過class文件對象,去使用該文件中的成員變量,構造方法,成員方法。首先必須得到class文件對象,既得到Class類的對象。

Class類:

            成員變量    Field
            構造方法    Constructor
            成員方法    Method
            獲得私有:getDeclaredXxx..

獲取class文件對象的方式:

A:Object類的getClass()方法
B:數據類型的靜態屬性class
C:Class類中的靜態方法(參數爲類的全路徑(帶包名))
                 public static Class<?> forName(String className)
D:基本內置類型的包裝類都有一個Type屬性

只要元素類型與維度都一樣,就是同一個Class

Class對象作用:

創建類的對象:
調用Class對象的newInstance()方法
       類必須有一個無參的構造方法
       類的構造方法的訪問權限需要足夠
  若沒有無參構造:
       通過Class類的getDeclaredConstructor(Class..parameterTypes)取得本類的指定形參類型的構造方法
       像構造方法的形參中傳遞一個對象數組進去,裏面包含了構造方法中所需要的各個參數。
       通過Constructor實例化對象

調用指定的方法
       通過反射,調用類中的方法,通過Method類完成
       通過Class類的getMethod(String name, Class...parameterTypes)方法取得一個Method對象,並設置此方法操作時所需要的參數類型
       之後使用Object invoke(Object obj, Object[] args)進行調用,並向方法中傳遞要設置的obj對象的參數信息。

Object invoke(Object obj, Object... args)
       Object對應原方法的返回值,若原方法無返回值,此時返回null
       若原方法若爲靜態方法,此時形參Object obj可爲null
       若原方法聲明爲private,則需要在調用此invoke()方法前,顯式調用方法對象的setAccessible(true)方法,將可訪問private的方法。 

setAccessible
       Method和Field、Constructor對象都有setAccessible()方法。
       setAccessible作用是啓動和禁用訪問安全檢查的開關。
       參數值爲true則指示反射的對象在使用時應該取消Java語言訪問檢查。
              提高反射的效率。如果代碼中必須用反射,而該句代碼需要頻繁的被調用,那麼請設置爲true.
              使得原本無法訪問的私有成員也可以訪問
       參數值爲false則指示反射的對象應該實施Java語言訪問檢查

反射操作泛型

       Java採用泛型擦除的機制來引入泛型,Java中的泛型僅僅是給編譯器javac使用的,確保數據的安全性和免去強制類型轉換問題,但是一旦編譯完成,所有和泛型有關的類型全部擦除
       爲了通過反射操作這些類型,Java新增了ParameterizedType,GenericArrayType,TypeVariable和WildcardType繼承幾種類型來代表不能被歸一到Class類中的類型但是又和原始類型齊名的類型。
       ParameterizedType:表示一種參數化類型,比如Collection<String>
       GenericArrayType:表示一種元素類型是參數化類型或者類型變量的數組類型
       TypeVariable:是各種類型變量的公共父接口
       WildcardType:代表一種通配符類型表達式

Java內存分析:

     堆:存放new的對象和數組;可以被所有的線程共享,不會存放別的對象應用
     棧:存放基本變量類型(會包含這個基本類型的具體數值);引用對象的變量(會存放這個引用在堆中的具體地址)
     方法區:可以被所有的線程共享;包含了所有的class和static變量

類的加載

       當程序要使用某個類是,如果該類還未被加載到內存中,則系統會通過加載,鏈接,初始化三步來實現對這個類進行初始化。
       加載
             將class文件字節碼內容加載到內存中,並將這些靜態數據轉換成方法區的運行時數據結構,然後生成一個代表這個類的java.lang.Class對象。
             任何類被使用時系統都會建立一個Class對象。
       鏈接:將Java類的二進制代碼合併到JVM的運行狀態之中的過程。
             驗證 是否有正確的內部結構,並和其他類協調一致(確保加載的類信息符合JVM規範,沒有安全方面的問題)
             準備 負責爲類的靜態成員分配內存,並設置默認初始化值(這些內存都將在方法區中進行分配)
             解析 將類的二進制數據中的符號引用替換爲直接引用(虛擬機常量池內的符號引用(常量名) 替換爲直接引用(地址 )的過程)
       初始化
             執行類構造器<clinit>()方法的過程。類構造器<clinit>()方法是由編譯期自動收集類中所有類變量的賦值動作和靜態代碼塊中的語句合併產生的。(類構造器是構造類信息的,不是構造該類對象的構造器)。
             當初始化一個類時,若發現其父類還沒有進行初始化,則需要先觸發其父類的初始化。
             虛擬機會保證一個類的<clinit>()方法在多線程環境中被正確加鎖和同步。

類的初始化

類的主動初始化
       當虛擬機啓動,先初始化main方法所在的類
       new一個類的對象
       調用類的靜態成員(除了final常量)和靜態方法
       調用java.lang.reflect包的方法對類進行反射調用
       當初始化一個類,如果其父類沒有被初始化,則先會初始化它的父類
類的被動引用(不會發生類的初始化)
       當訪問一個靜態域時,只有真正聲明這個域的類纔會被初始化。如:當通過子類引用父類的靜態變量,不會導致子類初始化
       通過數組定義類引用,不會觸發此類的初始化
       引用常量不會觸發此類的初始化(常量在鏈接階段就存入調用類的常量池中)

類加載器

類加載的作用:
       將class文件字節碼內容加載到內存中,並將這些靜態數據轉換成方法區的運行時數據結構,然後再堆中生成一個代表這個類的java,lang,Class對象,作爲方法區中類數據的訪問入口。
類緩存:
       標準的JavaSE類加載器可以按要求查找類,但一旦某個類被加載到類加載器中,它將維持加載(緩存)一段時間。不過JVM垃圾回收機制可以回收這些Class對象

       Bootstrap ClassLoader 根類加載器
               也被稱爲引導類加載器,負責Java核心類的加載,用來裝載核心類庫。該加載器無法直接獲取(比如System,String等。在JDK中JRE的lib目錄下rt.jar文件中)
       Extension ClassLoader 擴展類加載器
               負責JRE的擴展目錄中jar包的加載。(在JDK中JRE的lib目錄下ext目錄)
       Sysetm ClassLoader 系統類加載器
               負責在JVM啓動時加載來自java命令的class文件,以及classpath環境變量所指定的jar包和類路徑;是最常用的加載器
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章