單元測(cè)試
1. 前言
- 單元測(cè)試是指程序員寫(xiě)的測(cè)試代碼給自己的類中的方法進(jìn)行預(yù)期正確性的驗(yàn)證。
- 單元測(cè)試一旦寫(xiě)好了這些測(cè)試代碼,就可以一直使用,可以實(shí)現(xiàn)一定程度上的自動(dòng)化測(cè)試。
- 單元測(cè)試一般要使用框架進(jìn)行。
1.1 什么是框架?
框架是前人或者一些牛逼的技術(shù)公司在實(shí)戰(zhàn)或者研發(fā)中設(shè)計(jì)的一些優(yōu)良的設(shè)計(jì)方案或者成型的
代碼功能,作為一個(gè)完整的技術(shù)體系發(fā)行出來(lái)稱為框架。框架可以讓程序員快速擁有一個(gè)強(qiáng)大的解決方案,可以快速的開(kāi)發(fā)功能,提高效率并且直接就有了很好的性能。
單元測(cè)試的經(jīng)典框架:Junit
1.2 Junit是什么
- Junit是Java語(yǔ)言編寫(xiě)的第三方單元測(cè)試框架(工具類)
- Junit框架的方案可以幫助我們方便且快速的測(cè)試我們的代碼的正確性。
Junit單元測(cè)試框架的作用 - 用來(lái)對(duì)類中的方法功能進(jìn)行有目的的測(cè)試,以保證程序的正確性和穩(wěn)定性。
- 能夠獨(dú)立的測(cè)試某個(gè)方法或者所有方法的預(yù)期正確性。
1.3 Junit注解
- @Before // 修飾實(shí)例方法。在每個(gè)單元測(cè)試方法執(zhí)行之前執(zhí)行一次
- @After // 修飾實(shí)例方法。在每個(gè)單元測(cè)試方法執(zhí)行之后執(zhí)行一次
- @BeforeClass // 修飾靜態(tài)方法。在每個(gè)單元測(cè)試方法執(zhí)行之前執(zhí)行一次
- @AfterClass // 修飾靜態(tài)方法。在每個(gè)單元測(cè)試方法執(zhí)行之后執(zhí)行一次
- @Test
2. 概述
- 單元:在Java中,一個(gè)類就是一個(gè)單元
- 單元測(cè)試:程序猿用Junit編寫(xiě)的一小段代碼,用來(lái)對(duì)某個(gè)類中的某個(gè)方法進(jìn)行功能測(cè)試或業(yè)務(wù)邏輯測(cè)試。
3. 操作步驟
3.1 下載這個(gè)框架。(別人設(shè)計(jì)好的技術(shù)體系)
- 框架一般是jar包的形式,jar包里面都是class文件。
- class文件就是我們調(diào)用的核心代碼。
- Junit已經(jīng)被IDEA下載好了,可以直接導(dǎo)入到項(xiàng)目使用的。
3.2 直接用Junit測(cè)試代碼即可
先模擬業(yè)務(wù)代碼
-
寫(xiě)測(cè)試類
- 測(cè)試類的命名規(guī)范:以Test開(kāi)頭,以業(yè)務(wù)類類名結(jié)尾,使用駝峰命名法
- 業(yè)務(wù)名稱是:UserService
- 測(cè)試這個(gè)業(yè)務(wù)類的測(cè)試類:TestUserService
-
在測(cè)試類中寫(xiě)測(cè)試方法
- 測(cè)試方法的命名規(guī)則:以test開(kāi)頭,以業(yè)務(wù)方法名結(jié)尾
比如被測(cè)試業(yè)務(wù)方法名為:login,那么測(cè)試方法名就應(yīng)該叫:testLogin
- 測(cè)試方法的命名規(guī)則:以test開(kāi)頭,以業(yè)務(wù)方法名結(jié)尾
-
測(cè)試方法注意事項(xiàng)
- 必須是public修飾的,沒(méi)有返回值,沒(méi)有參數(shù)
- 必須使注解@Test修飾
3.3 如何運(yùn)行測(cè)試方法
- 選中方法名 --> 右鍵 --> Run '測(cè)試方法名' 運(yùn)行選中的測(cè)試方法
- 選中測(cè)試類類名 --> 右鍵 --> Run '測(cè)試類類名' 運(yùn)行測(cè)試類中所有測(cè)試方法
- 選中模塊名 --> 右鍵 --> Run 'All Tests' 運(yùn)行模塊中的所有測(cè)試類的所有測(cè)試方法
3.4 如何查看測(cè)試結(jié)果
綠色:表示測(cè)試通過(guò)
紅色:表示測(cè)試失敗,有問(wèn)題
反射
1. 概述
1.1 反射
- 是Java的高級(jí)技術(shù),是Java獨(dú)有的技術(shù)。是Java技術(shù)顯著的特點(diǎn)。
- 反射是指對(duì)于任何一個(gè)類,在運(yùn)行的時(shí)候都可以直接得到這個(gè)類全部成分。
- 在運(yùn)行時(shí),可以直接得到這個(gè)類的構(gòu)造器對(duì)象。(Constructor)
- 在運(yùn)行時(shí),可以直接得到這個(gè)類的成員變量。(Field)
- 在運(yùn)行時(shí),可以直接得到這個(gè)類的成員方法。(Method)
- 反射的核心思想和關(guān)鍵就是得到:編譯以后的class文件對(duì)象。
1.2 小結(jié):
- 反射必須工作在運(yùn)行時(shí)。
- 反射的關(guān)鍵是得到編譯以后的Class文件對(duì)象
- 反射可以在運(yùn)行時(shí)得到一個(gè)類的全部成分進(jìn)行一些操作。
2. 獲取
2.1 類
-
反射技術(shù)的第一步永遠(yuǎn)是先得到Class類對(duì)象:有三種方式獲取
- 類名.class
- 通過(guò)類的對(duì)象.getClass()方法
- Class.forName("類的全限名")
public static Class<?> forName(String className); -
Class類下的方法
// 獲得類名字符串:類名 String getSimpleName(); // 獲得類全名:包名+類名 String getName(); // 創(chuàng)建Class對(duì)象關(guān)聯(lián)類的對(duì)象 T newInstance() ;
2.2 構(gòu)造器
-
反射中Class類型獲取構(gòu)造器提供了很多的API
// 根據(jù)參數(shù)匹配獲取某個(gè)構(gòu)造器,只能拿public修飾的構(gòu)造器,幾乎不用! Constructor getConstructor(Class... parameterTypes); // 根據(jù)參數(shù)匹配獲取某個(gè)構(gòu)造器,只要申明就可以定位,不關(guān)心權(quán)限修飾符,建議使用! Constructor getDeclaredConstructor(Class... parameterTypes); // 獲取所有的構(gòu)造器,只能拿public修飾的構(gòu)造器。幾乎不用?。√趿?! 3. Constructor[] getConstructors(); // 獲取所有申明的構(gòu)造器,只要你寫(xiě)我就能拿到,無(wú)所謂權(quán)限。建議使用!! 4. Constructor[] getDeclaredConstructors(); -
小結(jié):
- 獲取全部構(gòu)造器,建議用getDeclaredConstructors();
- 獲取某個(gè)構(gòu)造器,建議用getDeclaredConstructor(Class... parameterTypes)
- 他們都無(wú)所謂權(quán)限,只要申明了就可以去?。?!
- 反射是破環(huán)封裝性的!!
2.3 成員變量
-
API
// 根據(jù)成員變量名獲得對(duì)應(yīng)Field對(duì)象,只能獲得public修飾 Field getField(String name); // 根據(jù)成員變量名獲得對(duì)應(yīng)Field對(duì)象,只要申明了就可以得到 Field getDeclaredField(String name); // 獲得所有的成員變量對(duì)應(yīng)的Field對(duì)象,只能獲得public的 Field[] getFields(); // 獲得所有的成員變量對(duì)應(yīng)的Field對(duì)象,只要申明了就可以得到 Field[] getDeclaredFields();
-
Field的方法:給成員變量賦值和取值
// 給對(duì)象注入某個(gè)成員變量數(shù)據(jù) void set(Object obj, Object value); // 獲取對(duì)象的成員變量的值 Object get(Object obj); // 暴力反射,設(shè)置為可以直接訪問(wèn)私有類型的屬性 void setAccessible(true); // 獲取屬性的類型,返回Class對(duì)象 Class getType(); // 獲取屬性的名稱 String getName();
2.4 方法
-
反射獲取類的Method方法對(duì)象
// 根據(jù)方法名和參數(shù)類型獲得對(duì)應(yīng)的方法對(duì)象,只能獲得public的 Method getMethod(String name,Class...args); // 根據(jù)方法名和參數(shù)類型獲得對(duì)應(yīng)的方法對(duì)象,包括private的 Method getDeclaredMethod(String name,Class...args); // 獲得類中的所有成員方法對(duì)象,返回?cái)?shù)組,只能獲得public修飾的且包含父類的 Method[] getMethods(); // 獲得類中的所有成員方法對(duì)象,返回?cái)?shù)組,只獲得本類申明的方法 Method[] getDeclaredMethods(); -
Method的方法
Object invoke(Object obj, Object... args)
- 觸發(fā)的是哪個(gè)對(duì)象的方法執(zhí)行。
- args:調(diào)用方法時(shí)傳遞的實(shí)例參數(shù)
3. 拓展:反射的作用
- 可以在運(yùn)行時(shí)得到一個(gè)類的全部成分然后操作。
- 可以破壞封裝性。
- 更重要的用途是適合:做Java高級(jí)框架,基本上主流框架都會(huì)基于反射設(shè)計(jì)一些通用功能。
注解
1. 注解的概念
1.1 注解
- 用在類上,方法上,成員變量方法,構(gòu)造器,...上對(duì)成分進(jìn)行編譯約束等操作的。
- 注解是JDK1.5的新特性。
- 注解相當(dāng)一種標(biāo)記,是類的組成部分,可以給類攜帶一些額外的信息。
- 注解是給編譯器或JVM看的,編譯器或JVM可以根據(jù)注解來(lái)完成對(duì)應(yīng)的功能。
1.2 注解作用
- 標(biāo)記。
- 方法重寫(xiě)約束 @Override
- 函數(shù)式接口約束。 @FunctionalInterface.
- 現(xiàn)今最牛逼的框架技術(shù)多半都是在使用注解和反射。
2. 自定義注解
2.1 自定義注解的格式
[修飾符] @interface 注解名{
// 注解屬性
}
2.2 小結(jié)
1.注解的定義是@interface
2.注解可以注釋類的成分,可以使用多個(gè)注解注釋同一個(gè)成分。
3. 注解的屬性
3.1 屬性的格式
- 格式1:數(shù)據(jù)類型 屬性名();
- 格式2:數(shù)據(jù)類型 屬性名() default 默認(rèn)值;
3.2 屬性適用的數(shù)據(jù)類型:
- 八種數(shù)據(jù)數(shù)據(jù)類型(int,short,long,double,byte
,char,boolean,float) - String,Class,注解類型。
- 以上類型的數(shù)組形式都支持
3.3 小結(jié):
- 注解的屬性在使用的時(shí)候需要有值!默認(rèn)值可以不賦值!
3.4 注解的特殊屬性名稱:value
- value屬性,如果只有一個(gè)value屬性的情況下,使用value屬性的時(shí)候可以省略value名稱不寫(xiě)!!
- 但是如果有多個(gè)屬性,那么value是不能省略的。
4. 元注解
4.1 簡(jiǎn)介
- 元注解是sun公司提供的。
- 元注解是用在自定義注解上的注解。
- 元注解是用來(lái)注解自定義注解的。
4.2 元注解有兩個(gè):
-
@Target:約束自定義注解只能在哪些地方使用,
作用:用來(lái)標(biāo)識(shí)注解使用的位置,如果沒(méi)有使用該注解標(biāo)識(shí),則自定義的注解可以使用在任意位置。
-
可使用的值定義在ElementType枚舉類中,常用值如下
TYPE,類,接口 FIELD, 成員變量 METHOD, 成員方法 PARAMETER, 方法參數(shù) CONSTRUCTOR, 構(gòu)造方法 LOCAL_VARIABLE, 局部變量 但是默認(rèn)的注解可以在類,方法,構(gòu)造器,成員變量,... 使用。
-
@Retention:申明注解的生命周期
- 作用:用來(lái)標(biāo)識(shí)注解的生命周期(有效范圍)
- 可使用的值定義在RetentionPolicy枚舉類中,常用值如下
- SOURCE:注解只作用在源碼階段,生成的字節(jié)碼文件中不存在
- CLASS:注解作用在源碼階段,字節(jié)碼文件階段,運(yùn)行階段不存在,默認(rèn)值
- RUNTIME:注解作用在源碼階段,字節(jié)碼文件階段,運(yùn)行階段(開(kāi)發(fā)常用)
- 申明注解的作用范圍:編譯時(shí),運(yùn)行時(shí)。
5. 注解解析
5.1 簡(jiǎn)介
- 我們會(huì)使用注解注釋一個(gè)類的成分,那么就設(shè)計(jì)到要解析出這些注解的數(shù)據(jù)。
- 開(kāi)發(fā)中經(jīng)常要知道一個(gè)類的成分上面到底有哪些注解,注解有哪些屬性數(shù)據(jù),這都需要進(jìn)行注解的解析。
5.2 與注解解析相關(guān)的接口
Annotation: 注解類型,該類是所有注解的父類。注解都是一個(gè)Annotation的對(duì)象
-
AnnotatedElement:該接口定義了與注解解析相關(guān)的方法
/* 所有的類成分Class, Method , Field , Constructor:都實(shí)現(xiàn)了AnnotatedElement接口 他們都擁有解析注解的能力: */ // 根據(jù)注解類型獲得對(duì)應(yīng)注解對(duì)象,會(huì)拿父類的注解 T getAnnotation(Class<T> annotationClass); // 獲得當(dāng)前對(duì)象上使用的所有注解,返回注解數(shù)組 Annotation[] getAnnotations() // 獲得當(dāng)前對(duì)象上使用的所有注解,返回注解數(shù)組,只包含本類的 Annotation[] getDeclaredAnnotations() // 根據(jù)注解類型獲得對(duì)應(yīng)注解對(duì)象 T getDeclaredAnnotation(Class<T> annotationClass) // 判斷當(dāng)前對(duì)象是否使用了指定的注解,如果使用了則返回true,否則false boolean isAnnotationPresent(Class<Annotation> annotationClass)
5.3 獲取注解數(shù)據(jù)的原理
- 注解在哪個(gè)成分上,我們就先拿哪個(gè)成分對(duì)象。
- 比如注解作用成員方法,則要獲得該成員方法對(duì)應(yīng)的Method對(duì)象,再來(lái)拿上面的注解
- 比如注解作用在類上,則要該類的Class對(duì)象,,再來(lái)拿上面的注解
- 比如注解作用在成員變量上,則要獲得該成員變量對(duì)應(yīng)的Field對(duì)象,再來(lái)拿上面的注解
6. 注解模擬Junit框架
定義若干個(gè)方法,只要加了MyTest注解,就可以被自動(dòng)觸發(fā)執(zhí)行。
-
分析:
- 定義一個(gè)自定義注解MyTest.
- 只能注解方法。
- 定義若干個(gè)方法,只要有@MyTest注解的方法就能被觸發(fā)執(zhí)行!!沒(méi)有這個(gè)注解的方法不能執(zhí)行!!
- 定義一個(gè)自定義注解MyTest.
小結(jié):
反射+注解+泛型通常是做大型框架的核心技術(shù)!!可以做通用框架技術(shù)!-
代碼實(shí)現(xiàn)
注解模擬Junit框架.png
動(dòng)態(tài)代理
1. 問(wèn)題:
- 我們發(fā)現(xiàn)我們的業(yè)務(wù)功能方法,前后的邏輯代碼幾乎都是一樣,只是中間部分不一樣
- 如果能夠讓業(yè)務(wù)功能只處理自己的核心邏輯,其他的不用寫(xiě)就可以完成,這時(shí)候需要用動(dòng)態(tài)代理了?。?/li>
2. 核心:
- 做一個(gè)代理類,把業(yè)務(wù)對(duì)象的交個(gè)代理類,返回被代理對(duì)象。
- 以后調(diào)用被代理對(duì)象的功能,會(huì)先觸發(fā)代理類執(zhí)行。
- 把業(yè)務(wù)對(duì)象 -> 轉(zhuǎn)成被代理的業(yè)務(wù)對(duì)象
3. 代理類
newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
- 參數(shù)一:給類的加載器,用于加載類。
- 參數(shù)二:被代理對(duì)象所實(shí)現(xiàn)的全部接口,因?yàn)楸淮淼墓δ芏荚诮涌谥卸x。
- 參數(shù)三:代理對(duì)象的處理方法:旅行社的功能。
