天天看點

Java SE 學習筆記 第七記

2012-07-25

1、每一個動态代理類都對應一個動态調用處理器InvocationHandler,因為動态代理類不具備方法的實作,動态代理類的方法依賴于動态調用處理器InvocationHandler的invoke方法來實作。

2、靜态代理的真實類和代理類關系是:真實類和代理類都是抽象角色的子類或者實作,并且代理類含有真實類的引用,通過代理類操作真實類。而政策模式對抽象角色子類的使用都是通過抽象角色來使用,政策模式的子類之間不能互相使用,因為一個子類沒有包含另一個子類的引用。

3、動态代理的真實類和代理類關系與靜态代理的真實類和代理類關系類似,差別在于動态類的定義和實作邏輯與靜态代理類不同。靜态代理每一個真實類都必須手動定義一個代理類,并且每一個靜态代理類中都必須重寫真實類中的每一個方法(即抽象角色中的方法),這麼一來,一旦真實類的數量多起來,需要手動定義的類數量将急劇上升,造成類數量的臃腫。而動态代理類的實作是通過InvocationHandler動态調用管理器和Proxy類在運作時動态定義和構造,定義一個包含Object引用變量的InvocationHandler實作類,就可以動态定義和構造任意真實類的代理,并且由于動态代理類的方法實作是傳遞給InvocationHandler的invoke方法實作,而InvocationHandler的invoke方法又是由這個方法中接收的參數method的invoke實作,是以動态代理類不需要對應真實類的每一個方法重寫,一律使用InvocationHandler的invoke動态實作真實類方法的重寫和調用。如此一來,動态代理的好處就是不用手動定義每一個代理類和代理類中的方法,被代理的獨享可以在運作時動态改變,動态代理類實作的接口也可以在運作時改變,進而實作了靈活的動态代理關系,降低了定義類的數量。

4、Java Annotation:Java注解,JDK1.5新增的特性。

5、JDK1.5提供的三個常用注解:

    1)@Override(位于java.lang.Override),隻能注解方法,在方法定義前使用該注解表示這個方法必須重寫一個父類或接口的方法,如果沒有則編譯不通過,該注解可達到在編譯時檢查有無重寫方法的作用。

    2)@Deprecated(位于java.lang.Deprecated),在方法定義前使用該注解表示該方法不建議被使用(一般是有更好的替代方法,或者該方法不夠安全),注解後該方法名會被删除線劃上,并且在調用該方法時會有不建議使用的警告。

    3)@SuppressWarnings(String[])(位于java.lang.SuppressWarning),可注解除了注解類型之外的其它所有類型,接收一個字元串數組,可注解一個類或者方法。注解的功能由接收的字元串數組決定,常用的參數有“unchecked”表示壓制檢查警告,“Deprecated”表示壓制使用不建議使用方法警告等等。當一個類被一個@SuppressWranings注解後,類中每一個方法都預設被這個注解注解,當類中方法還被自己的注解注解時,這個方法同時被兩個注解注解。

6、定義自己的注解類型:與定義接口類似,但是使用@Interface标志代替Interface,如public @Interface MyAnnotation{注解内容}。

7、當自定義注解中包含定義屬性時,要在屬性名後加(),如“public String value();”,否則編譯錯誤。如果要設定注解的預設值,要在屬性名的()後使用“default + 屬性值”的方式設定屬性的預設值。

8、使用帶屬性的自定義注解時,要在注解名後加(),并在括号内傳遞注解屬性值,如@MyAnnotation(“myAnnotation”)。同時,若注解的屬性名為value時,使用注解的括号内可直接寫屬性值,否則必須使用name=value的形式對應傳遞注解的屬性參數,當屬性有多個的時候,按照這個形式用逗号隔開就可以。

9、自定義注解的方法隻有使用@Interface一種,使用這個方法自定義的注解編譯器預設會繼承java.lang.annotation.Annotation接口。但是如果手動寫一個接口繼承這個java.lang.annotation.Annotation,這個接口也不是注解,就算是原來的這個java.lang.annotation.Annotation接口也不是一個注解。

10、如果自定義的注解與使用注解的類不在同一個包中,那麼同樣需要把包含注解的包導入到使用注解的類中,導入方法與導入類包的方法相同。

11、自定義的注解不能繼承其它的Annotation類型(其它已定義的注解)或者接口,但是可以使用其它已定義的注解來注解自定義的注解。

12、注解@Retention(位于java.lang.annotation.Retention):,隻能用于注解注解類型,使用@Retention注解自定義注解類型可以告知編譯器如何處理自定義的注解類型資訊。

13、枚舉類型RetentionPolicy(位于java.lang.annotation.RetentionPolicy):包含三個枚舉常量SOURCE、CLASS、RUNTIME。SOURCE常量表示編譯程式隻在編譯時使用注解資訊,但不将注解資訊儲存到class檔案中,是以不會在JVM中被讀取;CLASS枚舉常量表示編譯器會在編譯的時候使用注解資訊,并且會将注解資訊儲存到class檔案中,但是在VM加載class檔案時不讀取;RUNTIME枚舉常量表示編譯器在編譯時會使用注解資訊,并且會将注解資訊儲存到class檔案中,在JVM運作時加載class檔案會通過反射機制的API擷取注解資訊。

14、@Retention注解中包含一個RetentionPolicy枚舉類型的屬性(屬性名為value,是以使用這個注解時可以直接傳遞參數),并且屬性值預設是CLASS枚舉常量。通過使用@Retention注解并制定其枚舉常量來注解自定義注解類型,以此達到控制編譯器處理自定義注解類型資訊方法的目的。

15、通過實作反射機制的相關類擷取@Retention(RetentionPolicy.RUNTIME)注解的注解類型資訊:實作反射機制的相關類Class、Method、Constructor、Field、Package等都直接或間接實作了AnnotatedElement接口,AnnotatedElement接口中提供了四個與Annotation相關的方法。是以,使用反射機制的相關類調用實作了的AnnotatedElement接口方法,可以獲得該反射相關類代表的部分上是否存在@Retention(RetentionPolicy.RUNTIME)注解的注解類型以及其注解資訊。

16、AnnotatedElement接口四個方法:

    1)<T extends Annotation> getAnnotation(Class<T> annotationClass>,如果存在annotationClass(該參數為注解的.class)注解類型的注解,則傳回這個注解。

    2)Annotation[] getAnnotations(),如果存在注解則以注解數組形式全部傳回。

    3)Annotation[] getDeclaredAnnotations()傳回直接存在于此元素上的所有注釋。

    4)boolean isAnnotationPresent<Class<? extends Annotation>,接收一個Annotation類型,如果該元素上存在這個Annotation注解類型,則傳回true,否則傳回false。

17、通過反射機制相關類擷取注解引用變量後,可以利用這注解引用變量擷取該注解中屬性的值,擷取方法為“注解引用變量.注解屬性名()”,與對象擷取屬性值的方法後多加一個括号。

18、注解@Target(ElementType[]),隻能用于注解其它注解類型,接收一個ElementType枚舉常量數組,表示被注解的注解類型能用于注解什麼元素,由ElementType數組值決定。

19、ElementType枚舉類型常量值:ANNOTATION_TYPE(隻能注解注解類型)、CONSTRUCTOR(注解構造方法)、FIELD(注解屬性)、LOCAL_VARIABLE(注解局部變量)、METHOD(注解方法)、PACKAGE(注解包)、PARAMETER(注解參數)、TYPE(注解類、接口、注解類型、枚舉聲明)。

20、@Documented隻能用于注解注解類型,被它注解的注解類型所注解的元素在生成JavaDoc幫助文檔的時候,會在相應元素上顯示這個注解類型。如果沒有使用@Documented注解的注解類型在生成JavaDoc幫助文檔的時候不會儲存到文檔上。

21、Eclipse生成JavaDoc方法:Project-Generation Javadoc

22、@Inherited注解隻能注解注解類型,當一個元素被它注解的注解類型注解後,繼承該元素的元素能夠被繼承這個注解類型,反之則不會繼承。

————————————————————————————————————————————————————

2012-07-26

1、JUnit:Java單元測試,經典版本有JUnit3.8(完全基于反射機制設計)和JUnit4.x(基于反射機制和注解設計)

2、使用JUnit需要導入JUnit庫(JUnit.jar)。

3、使用JUnit3.8的類需要導入包import junit.framework.TestCase,并且使用的類需要繼承TestCase類,同時需要進行單元測試的方法名必須以test開頭,如果不以test開頭則進行JUnit測試的時候不會測試這個方法。

4、使用JUnit4.x的類需要導入包org.junit.Test,并且在需要測試的方法前添加注解@Test,那麼使用JUnit測試的時候就會測試這個方法,否則不會測試。

5、JUnit原理(執行步驟):

    1、先獲得需要測試類的Class對象。

    2、通過Class對象擷取測試類中所有public類型方法的Method數組。

    3、周遊Method數組,取出每一個Method對象。

    4、如果是JUnit3.8,則判斷Method對象對應的方法名是否是test開頭,是則執行這個方法,否則不執行;如果是JUnit4,則會調用每一個Method對象的isAnnotationPresent(Test.class),判斷方法是否被@Test注解,是則調用method.invoke()執行該方法,否則什麼都不做。

6、異常類:java.lang.Exception,java中所有的異常類都直接或間接的繼承Exception。

7、異常和錯誤:即Exception和java.lang.Error,它們都繼承與java.lang.Throwable類,Exception異常是指可以處理的程式錯誤,而Error錯誤是不可處理的程式錯誤。

8、運作時異常:也叫unchecked異常,java.lang.RuntimeException(直接繼承Exception)或者直接及間接繼承RuntimeException的異常,是運作期間抛出的異常,此類異常可以不必進行自行處理,JVM會自行處理,一般也不建議進行自行處理。

9、非運作時異常:也叫checked異常,所有直接或間接繼承Exception但非繼承RuntimeException的異常都叫非運作時異常,此類異常必須自行進行異常處理,可以通過try-catch-finally處理,也可以使用throws處理。

10、異常抛出的位置:1)當程式運作的代碼行出現異常時,會自動生成相應的異常類并抛出。2)new一個異常類,并使用throw關鍵字抛出。

11、處理異常的方法:

    1)try{}catch(Exception e){}finally{}:

    将可能出現異常的代碼放置到try後的{}代碼塊中,如果其中代碼出現異常,則會在出現異常的代碼行生成一個對應的異常對象并抛出和不再執行try中出現異常之後的代碼。

    此時會按照catch排列順序周遊try之後的catch(try之後可以跟多個catch,也可以将catch省略,但省略後必須跟finally),當其中一個catch參數異常類類型與抛出異常類類型符合時,則執行這個catch代碼塊中的方法。不存在抛出類型與所有catch不比對的情況,因為若存在可能抛出的異常與所有catch不比對時,程式在編譯的時候根本不能編譯通過。另外,比對catch參數的時候也隻會有一個catch比對,因為每次最多隻有一個異常抛出。特别的,由于比對catch是按照前後順序比對,如果多個catch的異常參數類型中存在繼承關系,那麼必須要将父類異常類型參數的catch排在子類catch之後,否則子類catch異常将永遠沒有機會調用,編譯時不能通過并會提示子類catch無法到達,而沒有繼承關系的catch則先後順序沒有關系。

    try-catch之後,無論異常是否處理,都會執行finally中的代碼,即使是try代碼塊中存在return,也會在return語句調用之前先執行finally代碼塊。但是如果try代碼塊中存在System.exit(0)語句,則不會執行finally代碼塊,因為exit(0)是結束JVM的語句。

    整個try-catch-finally執行完畢後,會繼續執行這個處理結構之後的代碼(如果處理結構中沒有catch則不會執行結構之後的代碼)。

    注:一般不将聲明變量的代碼放置到try代碼塊中,如果在try代碼快中聲明變量,那麼在try-catch-finally結構之外使用聲明的變量将會出現編譯錯誤。

    2)定義類時使用throws抛出相應異常:如果定義一個類的時候,類中代碼可能抛出異常,可以在定義類的參數清單括号後使用“throws+對應異常類[,對應異常類]”來将異常抛出但是不處理這個異常。處理異常的方法在于調用該類方法的方法中,要用try-catch-finally結構處理,如果調用該類方法的方法沒有處理,繼續使用throws将異常抛出到上一級調用方法。如果都沒有提供處理方法,繼續用throws抛出知道main方法都繼續throws,那麼這個異常會JVM處理。

    3)try-catch-finally結構和throws組合:在catch代碼塊中再使用throw抛出一個異常,并用throws将異常抛到方法外。這種做法通常用于捕獲代碼自動生成的異常,并将這個異常重新包裝成自定義的異常類,再以自定義的異常類抛出去處理,有利于形成具有特定處理資訊的異常類。

12、常見的運作時異常:NullPointerException,空指針異常,由于調用了某個對象的方法,但是該對象引用的值為null所導緻。

13、自定義異常類需要繼承一個異常類,一般是Exception,也有繼承RuntimeException,但比較少。Exception中含有一個帶參數的構造方法Exception(String str),str為異常的描述資訊,使用Exception繼承的printStackTrace()方法可以列印出異常描述資訊和異常出現位置(JVM處理異常一般也是調用這個方法)。

14、使用自定義異常類的方法通常是利用一些判斷結構,如if結構,在判斷出出現自定義異常的地方使用new,構造一個自定義異常類,并用throw将其抛出,同時在該方法聲明後面使用throws抛出。之後處理自定義的方法與其他異常類的處理方法一緻。