基础加强:反射和注解
目錄
一、Junit單元測試
1.什么是單元測試
2.Junit的使用步驟
3.單元測試中其它四個注解
二、反射
1.類的加載
2.什么是反射
3.反射在實際開發中的應用
4.反射中萬物皆對象的概念
5.反射的第一步獲取字節碼文件對象(Class對象)
6.Class對象中的三個常用方法
7.通過反射獲取構造方法
8.Constructor類中常用方法
9.通過反射獲取成員方法
10.Method類中常用方法
11.通過反射獲取成員屬性(了解)
12.Field類中常用方法(了解)
三、注解
1. JDK1.5的新特性
2.注解的兩個作用
3.常用注解介紹
4.自定義注解
5.給自定義注解添加屬性
6.使用自定義注解
7.自定義注解中的特殊屬性名
8.注解之元注解
(1)@Target元注解
(2)@Retention元注解
9.注解的解析
(1)確定注解所在的對象
(2)確定注解是否真實存在,獲取該注解對象
10.注解綜合練習
一、Junit單元測試
1.什么是單元測試
Junit是一個Java語言的單元測試框架,屬于白盒測試,簡單理解為可以用于取代java的main方法。Junit屬于第三方工具,需要導入jar包后使用。
2.Junit的使用步驟
(1)編寫測試類,簡單理解Junit可以用于取代java的main方法
(2)在測試類方法上添加注解 @Test
(3)@Test修飾的方法要求:public void 方法名() {…} ,方法名自定義建議test開頭,沒有參數。
(4)添加Junit庫到lib文件夾中,然后進行jar包關聯
3.單元測試中其它四個注解
@Before:修飾的方法會在測試方法之前被自動執行
@After:修飾的方法會在測試方法執行之后自動被執行
@BeforeClass:在所有的測試方法運行之前,只運行一次,而且必須用在靜態方法上。
@AfterClass:在所有的測試方法運行之后,只運行一次,而且必須用在靜態方法上。
二、反射
1.類的加載
當類的字節碼文件被加到內存之后,JVM自動為之創建一個對象(該對象中保存字節碼的所有信息),這個對象我們一般稱為字節碼文件對象或者Class對象
2.什么是反射
獲取Class對象,解剖它,從中取出構造方法,成員變量,成員方法,進而使用它們。
3.反射在實際開發中的應用
(1)編寫各種IDE(IDEA,Eclipse)
(2)編寫各種框架
4.反射中萬物皆對象的概念
(1)字節碼文件:Class對象
? ? ? ? ? ?(2)構造方法:Constructor對象
? ? ? ? ? ?(3)成員方法:Method對象
? ? ? ? ? ?(4)成員變量:Field對象
? ? ? ? ? ?(5)newInstance:創建對象
? ? ? ? ? ?(6)invoke:執行/調用
5.反射的第一步獲取字節碼文件對象(Class對象)
6.Class對象中的三個常用方法
String getSimpleName(); 獲得簡單類名,只是類名,沒有包
String getName(); 獲取完整類名,包含包名+類名
T newInstance()?;創建此 Class 對象所表示的類的一個新實例。要求:類必須有public的無參數構造方法
??newInstance()方法在JDK1.9之后過時了,需用下述方法替代:
? ? ? ? ? ? ? ? ? ? ? clazz.getDeclaredConstructor().newInstance()
7.通過反射獲取構造方法
(1)Constructor getConstructor(Class... parameterTypes)
根據參數類型獲取構造方法對象,只能獲得public修飾的構造方法。
如果不存在對應的構造方法,則會拋出 java.lang.NoSuchMethodException 異常。
(2)Constructor getDeclaredConstructor(Class... parameterTypes)
根據參數類型獲取構造方法對象,包括private修飾的構造方法。
如果不存在對應的構造方法,則會拋出 java.lang.NoSuchMethodException 異常。
(3)Constructor[] getConstructors()
獲取所有的public修飾的構造方法
(4)Constructor[] getDeclaredConstructors()
獲取所有構造方法,包括private修飾的構造方法
8.Constructor類中常用方法
(1)T newInstance(Object... initargs)
根據指定參數創建對象。
(2)void setAccessible(true)
暴力反射,設置為可以直接訪問私有類型的構造方法。
9.通過反射獲取成員方法
(1)Method getMethod("方法名", 方法的參數類型... 類型)
根據方法名和參數類型獲得一個方法對象,只能是獲取public修飾的
(2)Method getDeclaredMethod("方法名", 方法的參數類型... 類型)
根據方法名和參數類型獲得一個方法對象,包括private修飾的
(3)Method[] getMethods()
獲取所有的public修飾的成員方法,包括父類。
(4)Method[] getDeclaredMethods()
獲取當前類中所有的方法,包含私有的,不包括父類。
10.Method類中常用方法
(1)Object invoke(Object obj, Object... args)
根據參數args調用對象obj的該成員方法
如果obj=null,則表示該方法是靜態方法
(2)void setAccessible(boolean flag)
暴力反射,設置為可以直接調用私有修飾的成員方法
11.通過反射獲取成員屬性(了解)
public Field[] getFields():獲取public修飾的所有的變量對象
public Field[] getDeclaredFields():獲取所有的變量對象,包括私有
public Field getField(String name):獲取指定變量名的public修飾的變量對象
public Field getDeclaredField(String name):獲取指定變量名的變量對象,包括私有
12.Field類中常用方法(了解)
(1)Object get(Object obj):返回由該 Field表示的字段在指定對象上的值。
(2)void set(Object obj, Object value):將指定的對象參數中由此 Field對象表示的字段設置為指定的新值。
(3)void setAccessible(boolean flag) 將此反射對象的 accessible標志設置為指示的布爾值。 ?
(4)Class<?> getType():返回一個 Class對象,標識由該 Field對象表示的字段的聲明類型。 ?
三、注解
1. JDK1.5的新特性
一種標記,標記在類中,接口中,方法上,變量上。
2.注解的兩個作用
(1)編譯檢查
(2)框架的配置文件
3.常用注解介紹
@override(編譯檢查方法重寫是否正常)
@FunctionalInterface:編譯檢查是否符合函數式接口的要求(只有一個抽象方法)
@Oeprecated:編譯檢查是否過時
4.自定義注解
格式:
public @interface 注解名稱{
屬性列表;
}
5.給自定義注解添加屬性
(1)屬性的作用
可以讓用戶在使用注解時傳遞參數,讓注解的功能更加強大。
(2)屬性的格式
格式:格式1:數據類型 屬性名();
格式2:數據類型 屬性名() default 默認值;
(3)屬性定義實例
public @interface Student {String name(); // 姓名int age() default 18; // 年齡String gender() default "男"; // 性別}// 該注解就有了三個屬性:name,age,gender(4)屬性適用的數據類型
八種基本數據類型(int,float,boolean,byte,double,char,long,short)
String類型,Class類型,枚舉類型,注解類型
以上所有類型的一維數組
6.使用自定義注解
(1)定義一個注解:Book
包含屬性:String value() 書名
包含屬性:double price() 價格,默認值為 100
包含屬性:String[] authors() 多位作者
(2)使用注解
public class BookShelf {
@Book(value = "西游記",price = 998,authors = {"吳承恩","白求恩"})
? ? ? ? ? ? ? ? ?public void showBook(){
? ? ? ? ? ? ? ? ?}
}
(3)注意事項
①如果屬性有默認值,則使用注解的時候,這個屬性可以不用賦值。
②如果屬性沒有默認值,那么在使用注解時一定要給屬性賦值。
③屬性的出現順序隨意
④如果屬性是數組,那么需要使用{}括起來
7.自定義注解中的特殊屬性名
(1)當注解中只有一個屬性且名稱是value,在使用注解時給value屬性賦值可以直接給屬性值,無論value是單值元素還是數組類型。
(2)如果注解中除了value屬性還有其他屬性,且至少有一個屬性沒有默認值,則在使用注解給屬性賦值時,value屬性名不能省略。
8.注解之元注解
@Target
@Retention
(1)@Target元注解
作用:指明此注解用在哪個位置,如果不寫默認是任何地方都可以使用。
TYPE: 用在類,接口上
FIELD:用在成員變量上
METHOD: 用在方法上
PARAMETER:用在參數上
CONSTRUCTOR:用在構造方法上
LOCAL_VARIABLE:用在局部變量上
注意:以上六種屬性,是ElementType枚舉類中的靜態成員
(2)@Retention元注解
作用:定義該注解的生命周期(有效范圍)。
SOURCE:注解只存在于Java源代碼中,編譯生成的字節碼文件中就不存在了。
CLASS:注解存在于Java源代碼、編譯以后的字節碼文件中,運行的時候內存中沒有,默認值。
RUNTIME:注解存在于Java源代碼中、編譯以后的字節碼文件中、運行時內存中,程序可以通過反射獲取該注解。
注意:以上三種屬性,是RetentionPolicy枚舉類中的靜態成員
9.注解的解析
通過Java技術獲取注解數據的過程則稱為注解解析。
(1)確定注解所在的對象
如果注解在類上,獲取該類的字節碼文件對象
如果注解在構造上,先獲取字節碼文件對象,再獲取那個構造方法對象
如果注解在成員方法上,先獲取字節碼文件對象,再獲取那個成員方法對象
如果注解在成員變量上,現獲取字節碼文件對象,再獲取那個成員變量對象
(2)確定注解是否真實存在,獲取該注解對象
Anontation:所有注解類型的公共接口,類似所有類的父類是Object。
AnnotatedElement:定義了與注解解析相關的方法,常用方法以下四個:
?
boolean isAnnotationPresent(Class annotationClass); 判斷當前對象是否有指定的注解,有則返回true,否則返回false。
T getAnnotation(Class<T> annotationClass); 獲得當前對象上指定的注解對象。
Annotation[] getAnnotations(); 獲得當前對象及其從父類上繼承的所有的注解對象。
Annotation[] getDeclaredAnnotations();獲得當前對象上所有的注解對象,不包括父類的。
10.注解綜合練習
模擬Junit高級版本,自定義注解時,有一個屬性,加value
需求:執行main方法,讓Calculate類中被MyTest注解修飾的方法運行,value值是幾就運行幾次,其他方法不運行
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MyTest {int value(); } public class MyMethods {public void method1(){System.out.println("method1");}@MyTest(3)public void method2(){System.out.println("method2");}@MyTest(5)public void method3(){System.out.println("method3");}public void method4(){System.out.println("method4");}} //獲取加了注解的MyMethods類MyMethods methods = new MyMethods();//獲取該類的字節碼文件Class<? extends MyMethods> clazz = methods.getClass();//通過反射得到該類對象MyMethods myMethods = clazz.getDeclaredConstructor().newInstance();//通過反射得到所有方法Method[] methods1 = clazz.getMethods();//遍歷判斷是否有MyTest注解存在for (Method method : methods1) {if (method.isAnnotationPresent(MyTest.class)) {//如果存在,獲取value屬性值,執行相應次數的方法MyTest annotation = method.getAnnotation(MyTest.class);int value = annotation.value();for (int i = 0; i < value; i++) {method.invoke(myMethods);}}}?
總結
以上是生活随笔為你收集整理的基础加强:反射和注解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JDK1.8新特性:Stream流
- 下一篇: linux介绍及目录结构(一)