一,Junit單元測(cè)試
測(cè)試分類:
黑盒測(cè)試(不需要寫代碼,給輸入值,看程序是否能夠輸出期望的值)和白盒測(cè)試(需要寫代碼,關(guān)注程序具體的執(zhí)行流程)。
Junit使用步驟:
(1)定義一個(gè)測(cè)試類(測(cè)試用例)
建議:測(cè)試類名:被測(cè)試的類名Test;包名:xxx.xxx.xx.test
(2)定義測(cè)試方法:可以獨(dú)立運(yùn)行
建議:方法名:test測(cè)試的方法名;返回值:void;參數(shù)列表:空參。
(3)給方法加注解@Test
(4)導(dǎo)入Junit依賴
判定結(jié)果:
紅色:失??;綠色:成功。
一般會(huì)使用斷言操作來處理結(jié)果
Assert.assertEquals(3,result);//期望結(jié)果,斷言結(jié)果
/**
* 初始化方法:
* 用于資源申請(qǐng),所有測(cè)試方法在執(zhí)行之前都會(huì)先執(zhí)行該方法
*/
@Before
public void init(){
System.out.println("init...");
}
/**
* 釋放資源方法:
* 用于在所有測(cè)試方法執(zhí)行完后,都會(huì)自動(dòng)執(zhí)行該方法
*/
@After
public void close(){
System.out.println("close...");
}
二,反射
是框架設(shè)計(jì)的靈魂。
定義:將類的各個(gè)組成部分封裝為其他對(duì)象,這就是反射機(jī)制。
好處:
(1)可以在程序運(yùn)行過程中,操作這些對(duì)象。
(2)可以解耦,提高程序的可擴(kuò)展性。
獲取class對(duì)象的方式:
(1)Class.forName("全類名"):將字節(jié)碼文件加載進(jìn)內(nèi)存,返回Class對(duì)象。
多用于配置文件,將類名定義在配置文件中。讀取文件,加載類。
(2)類名.class:通過類名的屬性class獲取。
多用于參數(shù)的傳遞
(3)對(duì)象.getClass():getClass()方法在Object類中定義著。
多用于對(duì)象的獲取字節(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é)論:同一個(gè)字節(jié)碼文件(*.class)在一次程序運(yùn)行過程中,只會(huì)被加載一次,不論通過哪一種方式獲取的Class對(duì)象都是同一個(gè)。
Class對(duì)象功能:
獲取功能:獲取成員變量們,獲取構(gòu)造方法們,獲取成員方法們,獲取類名。
Field[] getFields()獲取所有public修飾的成員變量;
Field getField(String name)獲取指定名稱的public修飾的成員變量;
public static void main(String[] args) throws Exception {
//0,獲取Person的Class對(duì)象
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對(duì)象
Class personClass = Person.class;
/**
* 獲取構(gòu)造方法們
*/
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
//創(chuàng)建對(duì)象
Object person = constructor.newInstance("張三", 23);
System.out.println(person);
System.out.println("========");
//使用空參構(gòu)造器
Constructor constructor1 = personClass.getConstructor();
System.out.println(constructor1);
//創(chuàng)建對(duì)象
Object person1 = constructor1.newInstance();
System.out.println(person1);
//空參構(gòu)造可以使用簡化形式直接用class對(duì)象的newInstance()方法
Object o = personClass.newInstance();
System.out.println(o);
}
獲取成員方法們:
執(zhí)行方法:Object invoke(Object obj, Object... args)
獲取所有public修飾的方法:getMethods();
獲取方法名稱:String getName()
獲取類名:
//0,獲取Person的Class對(duì)象
Class personClass = Person.class;
String className = personClass.getName();
System.out.println(className);
}
案例:寫一個(gè)框架,可以幫我們創(chuàng)建任意類的對(duì)象,并且執(zhí)行其中任意方法。
實(shí)現(xiàn):(1)配置文件(2)反射
步驟:
(1)將需要?jiǎng)?chuàng)建的對(duì)象的全類名和需要執(zhí)行的方法定義在配置文件中;
(2)在程序中加載讀取配置文件
(3)使用反射技術(shù)來加載類文件進(jìn)內(nèi)存
(4)創(chuàng)建對(duì)象
(5)執(zhí)行方法
pro.properties文件:
className=cn.itcast.day12.demo01.test.Student
methodName=sleep
/**
* 框架類
*/
public class ReflectTest {
public static void main(String[] args) throws Exception {
/**
* 前提:不能改變?cè)擃惖娜魏未a
* 可以創(chuàng)建任意類的對(duì)象,可以執(zhí)行任意方法
*/
//1,加載配置文件
//1.1創(chuàng)建Properties對(duì)象
Properties pro = new Properties();
//1.2加載配置文件,轉(zhuǎn)換為一個(gè)集合
//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)建對(duì)象
Object obj = cls.newInstance();
//5,獲取方法對(duì)象
Method method = cls.getMethod(methodName);
//6,執(zhí)行方法
method.invoke(obj);
}
}
三,注解
概念:說明程序的,給計(jì)算機(jī)看的
JDK中預(yù)定義的一些注解:
- @Override:檢測(cè)該注解標(biāo)注的方法是否是繼承自父類的
- @Deprecated:該注解標(biāo)注的內(nèi)容表示已過時(shí)
- @SuppressWarnings:壓制警告
*一般傳遞參數(shù)all
自定義注解:
格式:元注解
public @interface 注解名稱{
屬性列表;//其實(shí)就是成員方法
}
本質(zhì):注解本質(zhì)上就是一個(gè)接口,該接口默認(rèn)繼承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation{}
屬性:接口中的抽象方法
- 屬性的返回值類型有下列取值:基本數(shù)據(jù)類型、字符串、枚舉、注解、以上類型的數(shù)組。
- 定義了屬性,在使用時(shí)需要給屬性賦值:如果定義屬性時(shí),使用default關(guān)鍵字給屬性默認(rèn)初始值,則使用注解時(shí),可以不進(jìn)行屬性的賦值;如果只有一個(gè)屬性需要賦值,并且屬性的名稱是value,則value可以省略,直接定義值即可;數(shù)組賦值時(shí),使用{}包裹,如果數(shù)組中只有一個(gè)值,則大括號(hào)可以省略。
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)前被描述的注解,會(huì)保留到class字節(jié)碼文件中,并被JVM讀取到。
(3)@Documented:描述注解是否被抽取到API文檔中
(4)@Inherited:描述注解是否被子類繼承
在程序使用(解析)注解:獲取注解中定義的屬性值
(1)獲取注解定義位置的對(duì)象(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();
}
/**
* 框架類:前提:不能改變?cè)擃惖娜魏未a,可以創(chuàng)建任意類的對(duì)象,可以執(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é)碼文件對(duì)象
Class<AnnoTest> annoTestClass = AnnoTest.class;
//2,獲取上邊的注解對(duì)象
//其實(shí)就是在內(nèi)存中生成了一個(gè)該注解接口的子類實(shí)現(xiàn)對(duì)象
Pro an = annoTestClass.getAnnotation(Pro.class);
//3,調(diào)用注解對(duì)象中定義的抽象方法,獲取返回值
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)建對(duì)象
Object obj = cls.newInstance();
//5,獲取方法對(duì)象
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
/**
* 簡單的測(cè)試框架
* 當(dāng)祝方法執(zhí)行后,會(huì)自動(dòng)自行被檢測(cè)的所有方法(加了Check注解的方法),判斷方法是否有異常,記錄到文件中
*/
public class TestCheck {
public static void main(String[] args) throws IOException {
//1,創(chuàng)建計(jì)算器對(duì)象
Calculator c = new Calculator();
//2,獲取字節(jié)碼文件對(duì)象
Class cls = c.getClass();
//3,獲取所有的方法
Method[] methods = cls.getMethods();
int num = 0;//出現(xiàn)異常的對(duì)象
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("本次測(cè)試一共出現(xiàn)"+ num +"次異常");
bw.flush();
bw.close();
}
}
執(zhí)行結(jié)果bug.txt
div方法除異常了
異常的名稱:ArithmeticException
異常的原因:/ by zero
======本次測(cè)試一共出現(xiàn)1次異常
小結(jié):
(1)以后大多數(shù)時(shí)候,我們會(huì)使用注解,而不是自定義注解。
(2)注解給誰用?編譯器,解析程序
(3)注解不是程序的一部分,可以理解為注解就是一個(gè)標(biāo)簽。