一,Junit單元測試
測試分類:
黑盒測試(不需要寫代碼飘蚯,給輸入值馍迄,看程序是否能夠輸出期望的值)和白盒測試(需要寫代碼福也,關(guān)注程序具體的執(zhí)行流程)。
Junit使用步驟:
(1)定義一個測試類(測試用例)
建議:測試類名:被測試的類名Test攀圈;包名:xxx.xxx.xx.test
(2)定義測試方法:可以獨立運行
建議:方法名:test測試的方法名暴凑;返回值:void;參數(shù)列表:空參赘来。
(3)給方法加注解@Test
(4)導(dǎo)入Junit依賴
判定結(jié)果:
紅色:失斚衷;綠色:成功犬辰。
一般會使用斷言操作來處理結(jié)果
Assert.assertEquals(3,result);//期望結(jié)果嗦篱,斷言結(jié)果
/**
* 初始化方法:
* 用于資源申請,所有測試方法在執(zhí)行之前都會先執(zhí)行該方法
*/
@Before
public void init(){
System.out.println("init...");
}
/**
* 釋放資源方法:
* 用于在所有測試方法執(zhí)行完后幌缝,都會自動執(zhí)行該方法
*/
@After
public void close(){
System.out.println("close...");
}
二灸促,反射
是框架設(shè)計的靈魂。
定義:將類的各個組成部分封裝為其他對象狮腿,這就是反射機制腿宰。
好處:
(1)可以在程序運行過程中,操作這些對象缘厢。
(2)可以解耦吃度,提高程序的可擴展性。
獲取class對象的方式:
(1)Class.forName("全類名"):將字節(jié)碼文件加載進(jìn)內(nèi)存贴硫,返回Class對象椿每。
多用于配置文件,將類名定義在配置文件中英遭。讀取文件间护,加載類。
(2)類名.class:通過類名的屬性class獲取挖诸。
多用于參數(shù)的傳遞
(3)對象.getClass():getClass()方法在Object類中定義著汁尺。
多用于對象的獲取字節(jié)碼的方式
Class cls1 = Class.forName("cn.itcast.day12.demo01.test.Person");
System.out.println(cls1);
//(2)
Class cls2 = Person.class;
System.out.println(cls2);
//(3)
Person p = new Person();
Class cls3 = p.getClass();
System.out.println(cls3);
結(jié)論:
同一個字節(jié)碼文件(*.class)在一次程序運行過程中,只會被加載一次多律,不論通過哪一種方式獲取的Class對象都是同一個痴突。
Class對象功能:
獲取功能:獲取成員變量們,獲取構(gòu)造方法們狼荞,獲取成員方法們辽装,獲取類名。
Field[] getFields()獲取所有public修飾的成員變量相味;
Field getField(String name)獲取指定名稱的public修飾的成員變量拾积;
public static void main(String[] args) throws Exception {
//0,獲取Person的Class對象
Class personClass = Person.class;
//1,獲取成員變量getFields(),getField(),getDeclaredFields(),getDeclaredField()
Field[] fields = personClass.getFields();
for(Field field : fields){
System.out.println(field);
}
System.out.println("======");
Field a = personClass.getField("a");
//獲取成員變量a的值
Person p = new Person();
Object value = a.get(p);
System.out.println(value);
//設(shè)置成員變量a的值
a.set(p,"張三");
System.out.println(p);
System.out.println("======");
//Field[] getDeclaredFields():獲取所有的成員變量,不考慮修飾符
Field[] declaredFields = personClass.getDeclaredFields();
for(Field declareField : declaredFields){
System.out.println(declareField);
}
//Fiels getDeclaredField(String name)
Field ad = personClass.getDeclaredField("age");
//忽略訪問權(quán)限修飾符的安全檢查
ad.setAccessible(true);//暴力反射
Object value2 = ad.get(p);
System.out.println(value2);
}
獲取構(gòu)造方法:
public static void main(String[] args) throws Exception {
//0,獲取Person的Class對象
Class personClass = Person.class;
/**
* 獲取構(gòu)造方法們
*/
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
//創(chuàng)建對象
Object person = constructor.newInstance("張三", 23);
System.out.println(person);
System.out.println("========");
//使用空參構(gòu)造器
Constructor constructor1 = personClass.getConstructor();
System.out.println(constructor1);
//創(chuàng)建對象
Object person1 = constructor1.newInstance();
System.out.println(person1);
//空參構(gòu)造可以使用簡化形式直接用class對象的newInstance()方法
Object o = personClass.newInstance();
System.out.println(o);
}
獲取成員方法們:
執(zhí)行方法:Object invoke(Object obj, Object... args)
獲取所有public修飾的方法:getMethods();
獲取方法名稱:String getName()
獲取類名:
//0,獲取Person的Class對象
Class personClass = Person.class;
String className = personClass.getName();
System.out.println(className);
}
案例:寫一個框架,可以幫我們創(chuàng)建任意類的對象拓巧,并且執(zhí)行其中任意方法。
實現(xiàn):(1)配置文件(2)反射
步驟:
(1)將需要創(chuàng)建的對象的全類名和需要執(zhí)行的方法定義在配置文件中玲销;
(2)在程序中加載讀取配置文件
(3)使用反射技術(shù)來加載類文件進(jìn)內(nèi)存
(4)創(chuàng)建對象
(5)執(zhí)行方法
pro.properties文件:
className=cn.itcast.day12.demo01.test.Student
methodName=sleep
/**
* 框架類
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
/**
* 前提:不能改變該類的任何代碼
* 可以創(chuàng)建任意類的對象,可以執(zhí)行任意方法
*/
//1,加載配置文件
//1.1創(chuàng)建Properties對象
Properties pro = new Properties();
//1.2加載配置文件贤斜,轉(zhuǎn)換為一個集合
//1.2.1獲取class目錄下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
//2,獲取配置文件中定義的數(shù)據(jù)
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
//3瘩绒,加載該類進(jìn)內(nèi)存
Class cls = Class.forName(className);
//4,創(chuàng)建對象
Object obj = cls.newInstance();
//5,獲取方法對象
Method method = cls.getMethod(methodName);
//6,執(zhí)行方法
method.invoke(obj);
}
}
三锁荔,注解
概念:說明程序的,給計算機看的
JDK中預(yù)定義的一些注解:
- @Override:檢測該注解標(biāo)注的方法是否是繼承自父類的
- @Deprecated:該注解標(biāo)注的內(nèi)容表示已過時
- @SuppressWarnings:壓制警告
*一般傳遞參數(shù)all
自定義注解:
格式:元注解
public @interface 注解名稱{
屬性列表蝙砌;//其實就是成員方法
}
本質(zhì):注解本質(zhì)上就是一個接口阳堕,該接口默認(rèn)繼承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation{}
屬性:接口中的抽象方法
- 屬性的返回值類型有下列取值:基本數(shù)據(jù)類型、字符串择克、枚舉恬总、注解、以上類型的數(shù)組肚邢。
- 定義了屬性壹堰,在使用時需要給屬性賦值:如果定義屬性時,使用default關(guān)鍵字給屬性默認(rèn)初始值骡湖,則使用注解時贱纠,可以不進(jìn)行屬性的賦值;如果只有一個屬性需要賦值响蕴,并且屬性的名稱是value谆焊,則value可以省略,直接定義值即可浦夷;數(shù)組賦值時辖试,使用{}包裹,如果數(shù)組中只有一個值军拟,則大括號可以省略剃执。
public @interface MyAnno2 {
int age();
}
@MyAnno2(age = 12)
public class DemoAnnotation {
}
枚舉
public enum Person {
p1,p2;
}
public @interface MyAnno {
Person per();
}
@MyAnno(per = Person.p1)
public class Worker {
}
所有屬性賦值:
public @interface MyAnno {
Person per();
MyAnno2 anno2();
String[] strs();
int show1();
String show2();
}
@MyAnno(per = Person.p1,anno2 = @MyAnno2,strs = {"abc", "bbb"},show1 = 1,show2 = "abc")
public class Worker {
}
元注解:用于描述注解的注解
(1)@Target:描述注解能夠作用的位置
ElementType取值:TYPE可以作用于類上;METHOD:可以作用于方法上懈息;FIELD:可以作用于成員變量上
@Target(value={ElementType.TYPE,})//表示該MyAnno2注解只能作用于類上
(2)@Retention:描述注解被保留的階段
@Retention(RetentionPolicy.RUNTIME):當(dāng)前被描述的注解肾档,會保留到class字節(jié)碼文件中,并被JVM讀取到。
(3)@Documented:描述注解是否被抽取到API文檔中
(4)@Inherited:描述注解是否被子類繼承
在程序使用(解析)注解:獲取注解中定義的屬性值
(1)獲取注解定義位置的對象(Class怒见,Method俗慈,F(xiàn)Ield)
(2)獲取指定的注解:getAnnotation(Class)
(3)調(diào)用注解中的抽象方法獲取配置的屬性值
/**
* 描述需要執(zhí)行的類名和方法名
*/
@Target({ElementType.TYPE})//可以作用在類上
@Retention(RetentionPolicy.RUNTIME)//希望被保留在RUNTIME階段
public @interface Pro {
String className();
String methodName();
}
/**
* 框架類:前提:不能改變該類的任何代碼,可以創(chuàng)建任意類的對象遣耍,可以執(zhí)行任意方法
*/
@Pro(className = "cn.itcast.day12.demo01.demo06.Demo1",methodName = "show")
public class AnnoTest {
public static void main(String[] args) throws Exception{
//1闺阱,解析注解
//1.1獲取該類的字節(jié)碼文件對象
Class<AnnoTest> annoTestClass = AnnoTest.class;
//2,獲取上邊的注解對象
//其實就是在內(nèi)存中生成了一個該注解接口的子類實現(xiàn)對象
Pro an = annoTestClass.getAnnotation(Pro.class);
//3,調(diào)用注解對象中定義的抽象方法,獲取返回值
String className = an.className();
String methodName = an.methodName();
System.out.println(className);
System.out.println(methodName);
//3舵变,加載該類進(jìn)內(nèi)存
Class cls = Class.forName(className);
//4酣溃,創(chuàng)建對象
Object obj = cls.newInstance();
//5,獲取方法對象
Method method = cls.getMethod(methodName);
//6,執(zhí)行方法
method.invoke(obj);
}
}
案例:
Check.java
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {
}
Calculator.java
@Check
public void add(){
System.out.println("1+0="+(1+0));
}
@Check
public void sub(){
System.out.println("1-0="+(1-0));
}
@Check
public void mul(){
System.out.println("1*0="+(1*0));
}
@Check
public void div(){
System.out.println("1/0="+(1 / 0));
}
public void show(){
System.out.println("永無bug...");
}
}
TestCheck.java
/**
* 簡單的測試框架
* 當(dāng)祝方法執(zhí)行后,會自動自行被檢測的所有方法(加了Check注解的方法)纪隙,判斷方法是否有異常赊豌,記錄到文件中
*/
public class TestCheck {
public static void main(String[] args) throws IOException {
//1,創(chuàng)建計算器對象
Calculator c = new Calculator();
//2绵咱,獲取字節(jié)碼文件對象
Class cls = c.getClass();
//3碘饼,獲取所有的方法
Method[] methods = cls.getMethods();
int num = 0;//出現(xiàn)異常的對象
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for(Method method : methods) {
//4,判斷方法上是否有Check注解艾恼,有即執(zhí)行
if (method.isAnnotationPresent(Check.class)) {
try {
method.invoke(c);
} catch (Exception e) {
//5钠绍,捕獲異常
//記錄到文件中
num++;
bw.write(method.getName() + "方法出異常了");
bw.newLine();
bw.write("異常的名稱:" + e.getCause().getClass().getSimpleName());
bw.newLine();
bw.write("異常的原因:" + e.getCause().getMessage());
bw.newLine();
bw.write("======");
}
}
}
bw.write("本次測試一共出現(xiàn)"+ num +"次異常");
bw.flush();
bw.close();
}
}
執(zhí)行結(jié)果bug.txt
div方法除異常了
異常的名稱:ArithmeticException
異常的原因:/ by zero
======本次測試一共出現(xiàn)1次異常
小結(jié):
(1)以后大多數(shù)時候五慈,我們會使用注解泻拦,而不是自定義注解忽媒。
(2)注解給誰用?編譯器架曹,解析程序
(3)注解不是程序的一部分闹瞧,可以理解為注解就是一個標(biāo)簽奥邮。