Junit單元測試、反射剖踊、注解

今日內(nèi)容

1. Junit單元測試
2. 反射
3. 注解

Junit單元測試:

* 測試分類:
    1. 黑盒測試:不需要寫代碼庶弃,給輸入值衫贬,看程序是否能夠輸出期望的值。
    2. 白盒測試:需要寫代碼的歇攻。關(guān)注程序具體的執(zhí)行流程固惯。

* Junit使用:白盒測試
    * 步驟:
        1. 定義一個測試類(測試用例)
            * 建議:
                * 測試類名:被測試的類名Test       CalculatorTest
                * 包名:xxx.xxx.xx.test        cn.itcast.test

        2. 定義測試方法:可以獨立運行
            * 建議:
                * 方法名:test測試的方法名        testAdd()  
                * 返回值:void
                * 參數(shù)列表:空參

        3. 給方法加@Test
        4. 導(dǎo)入junit依賴環(huán)境

    * 判定結(jié)果:
        * 紅色:失敗
        * 綠色:成功
        * 一般我們會使用斷言操作來處理結(jié)果
            * Assert.assertEquals(期望的結(jié)果,運算的結(jié)果);

    * 補充:
        * @Before:
            * 修飾的方法會在測試方法之前被自動執(zhí)行
        * @After:
            * 修飾的方法會在測試方法執(zhí)行之后自動被執(zhí)行
public class refilectdemo {
    public static void main(String[] args) throws ClassNotFoundException {
        //forName將字節(jié)碼文件加載到內(nèi)存中返回Class對象  獲取字節(jié)碼文件的三種方式
        Class<?> aClass = Class.forName("JavaWeb開發(fā).day_01基礎(chǔ)加強.Junit.CalcClass");
        System.out.println(aClass);
        //第二種方式  多用于傳參
        Class aClass1 = CalcClass.class;
        System.out.println(aClass1);
        //第三種方式
        CalcClass calcClass = new CalcClass();
        Class aClass2 = calcClass.getClass();

//        ClassLoader classLoader = aClass.getClassLoader();
//        System.out.println("類加載器 :"+classLoader);
        System.out.println(aClass2);

        System.out.println(aClass==aClass1); //內(nèi)存地址相同 屬于同一個對象
        System.out.println(aClass==aClass2);
        System.out.println(aClass1==aClass2);
    }
}

反射:框架設(shè)計的靈魂

* 框架:半成品軟件〗墒兀可以在框架的基礎(chǔ)上進行軟件開發(fā)葬毫,簡化編碼
* 反射:將類的各個組成部分封裝為其他對象,這就是反射機制
    * 好處:
        1. 可以在程序運行過程中屡穗,操作這些對象供常。
        2. 可以解耦,提高程序的可擴展性鸡捐。
* 獲取Class對象的方式:
    1. Class.forName("全類名"):將字節(jié)碼文件加載進內(nèi)存,返回Class對象
        * 多用于配置文件麻裁,將類名定義在配置文件中箍镜。讀取文件,加載類
    2. 類名.class:通過類名的屬性class獲取
        * 多用于參數(shù)的傳遞
    3. 對象.getClass():getClass()方法在Object類中定義著煎源。
        * 多用于對象的獲取字節(jié)碼的方式

    * 結(jié)論:
        同一個字節(jié)碼文件(*.class)在一次程序運行過程中色迂,只會被加載一次,不論通過哪一種方式獲取的Class對象都是同一個手销。
* Class對象功能:
    * 獲取功能:
        1. 獲取成員變量們
            * Field[] getFields() :獲取所有public修飾的成員變量
            * Field getField(String name)   獲取指定名稱的 public修飾的成員變量

            * Field[] getDeclaredFields()  獲取所有的成員變量歇僧,不考慮修飾符
            * Field getDeclaredField(String name)  
        2. 獲取構(gòu)造方法們
            * Constructor<?>[] getConstructors()  
            * Constructor<T> getConstructor(類<?>... parameterTypes)  

            * Constructor<T> getDeclaredConstructor(類<?>... parameterTypes)  
            * Constructor<?>[] getDeclaredConstructors()  
        3. 獲取成員方法們:
            * Method[] getMethods()  
            * Method getMethod(String name, 類<?>... parameterTypes)  

            * Method[] getDeclaredMethods()  
            * Method getDeclaredMethod(String name, 類<?>... parameterTypes)  

        4. 獲取全類名    
            * String getName()  


* Field:成員變量
    * 操作:
        1. 設(shè)置值
            * void set(Object obj, Object value)  
        2. 獲取值
            * get(Object obj) 

        3. 忽略訪問權(quán)限修飾符的安全檢查
            * setAccessible(true):暴力反射



* Constructor:構(gòu)造方法
    * 創(chuàng)建對象:
        * T newInstance(Object... initargs)  

        * 如果使用空參數(shù)構(gòu)造方法創(chuàng)建對象,操作可以簡化:Class對象的newInstance方法


* Method:方法對象
    * 執(zhí)行方法:
        * Object invoke(Object obj, Object... args)  

    * 獲取方法名稱:
        * String getName:獲取方法名


* 案例:
    * 需求:寫一個"框架"锋拖,不能改變該類的任何代碼的前提下诈悍,可以幫我們創(chuàng)建任意類的對象,并且執(zhí)行其中任意方法
        * 實現(xiàn):
            1. 配置文件
            2. 反射
        * 步驟:
            1. 將需要創(chuàng)建的對象的全類名和需要執(zhí)行的方法定義在配置文件中
            2. 在程序中加載讀取配置文件
            3. 使用反射技術(shù)來加載類文件進內(nèi)存
            4. 創(chuàng)建對象
            5. 執(zhí)行方法

創(chuàng)建一個框架

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //創(chuàng)建一個properties對象
        Properties pro = new Properties();
        //創(chuàng)建一個類加載器
        ClassLoader classLoader = ReflectTest.class.getClassLoader();
        //調(diào)用getResourceAsStream方法獲取資源對應(yīng)的字節(jié)流
        InputStream is = classLoader.getResourceAsStream("pro.properties");
        System.out.println(is);
    //調(diào)用load方法獲取里面的鍵值對
        pro.load(is);

        //獲取配置文件中鍵值對
        String className = pro.getProperty("className");
        String methodName = pro.getProperty("methodName");

        //將對象加入內(nèi)存中
        Class aClass = Class.forName(className);
        //創(chuàng)建一個新的對象
        Object o = aClass.getDeclaredConstructor().newInstance();
        //獲取方法
        Method method = aClass.getMethod(methodName);
        //執(zhí)行方法
        method.invoke(o);


    }
}

Class類總結(jié)

Class類也是類的一種兽埃,與class關(guān)鍵字是不一樣的侥钳。

手動編寫的類被編譯后會產(chǎn)生一個Class對象,其表示的是創(chuàng)建的類的類型信息柄错,而且這個Class對象保存在同名.class的文件中(字節(jié)碼文件)舷夺,比如創(chuàng)建一個Shapes類,編譯Shapes類后就會創(chuàng)建其包含Shapes類相關(guān)類型信息的Class對象售貌,并保存在Shapes.class字節(jié)碼文件中给猾。

每個通過關(guān)鍵字class標(biāo)識的類,在內(nèi)存中有且只有一個與之對應(yīng)的Class對象來描述其類型信息颂跨,無論創(chuàng)建多少個實例對象敢伸,其依據(jù)的都是用一個Class對象。

Class類只存私有構(gòu)造函數(shù)毫捣,因此對應(yīng)Class對象只能有JVM創(chuàng)建和加載

Class類的對象作用是運行時提供或獲得某個對象的類型信息详拙,這點對于反射技術(shù)很重要(關(guān)于反射稍后分析)帝际。

獲取Class類的幾種方式 和 類加載的初始化

import java.util.*;
/*因為staticFinal屬于編譯期靜態(tài)常量,在編譯階段通過常量傳播優(yōu)化的方式將Initable類的常量
staticFinal存儲到了一個稱為NotInitialization類的常量池中饶辙,在以后對Initable類常量staticFinal的
引用實際都轉(zhuǎn)化為對NotInitialization類對自身常量池的引用蹲诀,所以在編譯期后,對編譯期常量的引用都將
在NotInitialization類的常量池獲取,這也就是引用編譯期靜態(tài)常量不會觸發(fā)Initable類初始化的重要原因
但在之后調(diào)用了Initable.staticFinal2變量后就觸發(fā)了Initable類的初始化弃揽,注意staticFinal2雖然被static和final修飾脯爪,但其值在編譯期并不能確定,
因此staticFinal2并不是編譯期常量矿微,使用該變量必須先初始化Initable類痕慢。
Initable2和Initable3類中都是靜態(tài)成員變量并非編譯期常量,引用都會觸發(fā)初始化涌矢。
**/
class Initable {
    //編譯期靜態(tài)常量
    static final int staticFinal = 47;
    //非編期靜態(tài)常量
    static final int staticFinal2 =
            ClassInitialization.rand.nextInt(1000);
    static {
        System.out.println("Initializing Initable");
    }
}

class Initable2 {
    //靜態(tài)成員變量
     static int staticNonFinal = 147;
     //jing
    static {
        System.out.println("Initializing Initable2");
    }
}

class Initable3 {
    //靜態(tài)成員變量
    static int staticNonFinal = 74;
    static {
        System.out.println("Initializing Initable3");
    }
}

public class ClassInitialization {
    public static Random rand = new Random();
    public static void main(String[] args) throws Exception {
        //字面常量獲取方式獲取Class對象
        Class initable = Initable.class;
        System.out.println("After creating Initable ref");
        //不觸發(fā)類初始化
        System.out.println(Initable.staticFinal);
        //會觸發(fā)類初始化
        System.out.println(Initable.staticFinal2);
        //會觸發(fā)類初始化
        System.out.println("============");
        System.out.println(Initable2.staticNonFinal);
        //forName方法獲取Class對象
//        Class initable3 = Class.forName("cn.Initable3");
        System.out.println("After creating Initable3 ref");
        System.out.println(Initable3.staticNonFinal);
    }
}

注解:

* 概念:說明程序的掖举。給計算機看的
* 注釋:用文字描述程序的。給程序員看的

* 定義:注解(Annotation)娜庇,也叫元數(shù)據(jù)塔次。一種代碼級別的說明函荣。它是JDK1.5及以后版本引入的一個特性洋魂,與類官觅、接口恩袱、枚舉是在同一個層次资铡。它可以聲明在包变泄、類亮元、字段袖外、方法汁掠、局部變量略吨、方法參數(shù)等的前面,用來對這些元素進行說明调塌,注釋晋南。
* 概念描述:
    * JDK1.5之后的新特性
    * 說明程序的
    * 使用注解:@注解名稱
    
package JavaWeb開發(fā).day_01基礎(chǔ)加強.annotate;

/**
 * @author grey  //作者
 * @since 1.5   //JDK版本
 * @version 1.0  //版本
 */
public class annotationDemo {
    /**
     * 求和
     * @param a 整數(shù)
     * @param b 整數(shù)
     * @return a和b的和
     */
    public int method(int a,int b){
        return a+b;
    }
}

?
? * 作用分類:
? ①編寫文檔:通過代碼里標(biāo)識的注解生成文檔【生成文檔doc文檔】
? ②代碼分析:通過代碼里標(biāo)識的注解對代碼進行分析【使用反射】
? ③編譯檢查:通過代碼里標(biāo)識的注解讓編譯器能夠?qū)崿F(xiàn)基本的編譯檢查【Override】

* JDK中預(yù)定義的一些注解
    * @Override :檢測被該注解標(biāo)注的方法是否是繼承自父類(接口)的
    * @Deprecated:該注解標(biāo)注的內(nèi)容,表示已過時
    * @SuppressWarnings:壓制警告
        * 一般傳遞參數(shù)all  @SuppressWarnings("all")
    * @FunctionalInterface 函數(shù)式接口

* 自定義注解
    * 格式:
        元注解
        public @interface 注解名稱{
            屬性列表;
        }

    * 本質(zhì):注解本質(zhì)上就是一個接口羔砾,該接口默認(rèn)繼承Annotation接口
        * public interface MyAnno extends java.lang.annotation.Annotation {}

    * 屬性:接口中的抽象方法
        * 要求:
            1. 屬性的返回值類型有下列取值
                * 基本數(shù)據(jù)類型
                * String
                * 枚舉
                * 注解
                * 以上類型的數(shù)組

            2. 定義了屬性负间,在使用時需要給屬性賦值
                1. 如果定義屬性時,使用default關(guān)鍵字給屬性默認(rèn)初始化值姜凄,則使用注解時政溃,可以不進行屬性的賦值。
                2. 如果只有一個屬性需要賦值态秧,并且屬性的名稱是value董虱,則value可以省略,直接定義值即可。
                3. 數(shù)組賦值時愤诱,值使用{}包裹云头。如果數(shù)組中只有一個值,則{}可以省略
    
    * 元注解:用于描述注解的注解
        * @Target:描述注解能夠作用的位置
            * ElementType取值:
                * TYPE:可以作用于類上
                * METHOD:可以作用于方法上
                * FIELD:可以作用于成員變量上
        * @Retention:描述注解被保留的階段
            * @Retention(RetentionPolicy.RUNTIME):當(dāng)前被描述的注解淫半,會保留到class字節(jié)碼文件中溃槐,并被JVM讀取到
        * @Documented:描述注解是否被抽取到api文檔中
        * @Inherited:描述注解是否被子類繼承


* 在程序使用(解析)注解:獲取注解中定義的屬性值
    1. 獲取注解定義的位置的對象  (Class,Method,Field)
    2. 獲取指定的注解
        * getAnnotation(Class)
        //其實就是在內(nèi)存中生成了一個該注解接口的子類實現(xiàn)對象

                public class ProImpl implements Pro{
                    public String className(){
                        return "cn.itcast.annotation.Demo1";
                    }
                    public String methodName(){
                        return "show";
                    }
                }
    3. 調(diào)用注解中的抽象方法獲取配置的屬性值


* 案例:簡單的測試框架
* 小結(jié):
    1. 以后大多數(shù)時候科吭,我們會使用注解昏滴,而不是自定義注解
    2. 注解給誰用?
        1. 編譯器
        2. 給解析程序用
    3. 注解不是程序的一部分对人,可以理解為注解就是一個標(biāo)簽

判斷程序出現(xiàn)異常數(shù)量案例

@Pro(className = "cn.Calculator")
public class CheckTest {
    public static void main(String[] args) throws Exception {
        ////獲取注解定義的位置的對象
        Class<CheckTest> aClass = CheckTest.class;
        //獲取指定的注解
        Pro pro = aClass.getAnnotation(Pro.class);
        //獲取被修飾類的名稱
        String className = pro.className();
        //將class對象加載到內(nèi)存中
        Class<?> aClass1 = aClass.forName(className);
        //創(chuàng)建一個classname對象
        Object o = aClass1.getDeclaredConstructor().newInstance();
        //獲取所有的方法并存入內(nèi)存中
        Method[] methods = aClass1.getDeclaredMethods();
        //創(chuàng)建一個輸出流對象 將錯誤信息存入.txt文件
        BufferedWriter fw=new BufferedWriter(new FileWriter("Bug.txt"));
        int count=0; //計算出錯數(shù)量
        for (Method method : methods) {
            if (method.isAnnotationPresent(Check.class)){
                try{
                    method.invoke(o); //執(zhí)行方法
                }catch (Exception e){
                    count++;
                    fw.write("哎呀谣殊!"+method.getName()+"方法出現(xiàn)異常了");
                    fw.newLine();
                    fw.write("異常名稱: "+e.getCause().getClass().getSimpleName());
                    fw.newLine();
                    fw.write("異常詳情: "+e.getCause().getMessage());
                    fw.newLine();
                }
            }
        }
        fw.write("共有 "+count+"個異常");
        fw.flush();
        fw.close();


    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請通過簡信或評論聯(lián)系作者牺弄。
  • 序言:七十年代末姻几,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子势告,更是在濱河造成了極大的恐慌鲜棠,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,406評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件培慌,死亡現(xiàn)場離奇詭異,居然都是意外死亡柑爸,警方通過查閱死者的電腦和手機吵护,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,732評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來表鳍,“玉大人馅而,你說我怎么就攤上這事∑┦ィ” “怎么了瓮恭?”我有些...
    開封第一講書人閱讀 163,711評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長厘熟。 經(jīng)常有香客問我屯蹦,道長,這世上最難降的妖魔是什么绳姨? 我笑而不...
    開封第一講書人閱讀 58,380評論 1 293
  • 正文 為了忘掉前任登澜,我火速辦了婚禮,結(jié)果婚禮上飘庄,老公的妹妹穿的比我還像新娘脑蠕。我一直安慰自己,他們只是感情好谴仙,可當(dāng)我...
    茶點故事閱讀 67,432評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著揩局,像睡著了一般。 火紅的嫁衣襯著肌膚如雪哼审。 梳的紋絲不亂的頭發(fā)上谐腰,一...
    開封第一講書人閱讀 51,301評論 1 301
  • 那天,我揣著相機與錄音十气,去河邊找鬼。 笑死砸西,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的址儒。 我是一名探鬼主播芹枷,決...
    沈念sama閱讀 40,145評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼莲趣!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起喧伞,我...
    開封第一講書人閱讀 39,008評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎翁逞,沒想到半個月后溉仑,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挖函,經(jīng)...
    沈念sama閱讀 45,443評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡浊竟,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,649評論 3 334
  • 正文 我和宋清朗相戀三年振定,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片吩案。...
    茶點故事閱讀 39,795評論 1 347
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖靠益,靈堂內(nèi)的尸體忽然破棺而出丧肴,到底是詐尸還是另有隱情胧后,我是刑警寧澤,帶...
    沈念sama閱讀 35,501評論 5 345
  • 正文 年R本政府宣布纸巷,位于F島的核電站眶痰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏竖伯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,119評論 3 328
  • 文/蒙蒙 一祟偷、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧修肠,春花似錦户盯、人聲如沸氛赐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,731評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至撩笆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間夕冲,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,865評論 1 269
  • 我被黑心中介騙來泰國打工泣栈, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人南片。 一個月前我還...
    沈念sama閱讀 47,899評論 2 370
  • 正文 我出身青樓疼进,卻偏偏與公主長得像薪缆,于是被迫代替她去往敵國和親伞广。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,724評論 2 354