泛型 & 注解 & Log4J日志組件

掌握的知識 : 基本用法、泛型擦除、泛型類/泛型方法/泛型接口、泛型關(guān)鍵字、反射泛型(案例)

泛型

  • 概述 : 泛型是JDK1.5以后才有的, 可以在編譯時(shí)期進(jìn)行類型檢查,且可以避免頻繁類型轉(zhuǎn)化
// 運(yùn)行時(shí)期異常 
    @Test
    public void testGeneric() throws Exception {
        // 集合的聲明
        List list = new ArrayList();
        list.add("China");
        list.add(1);
        // 集合的使用
        String str = (String) list.get(1);
    }
    // 使用泛型
    @Test
    public void testGeneric2() throws Exception {
        // 聲明泛型集合的時(shí)候指定元素的類型
        List<String> list = new ArrayList<String>();
        list.add("China");
//      list.add(1);// 編譯時(shí)期報(bào)錯(cuò)   
        String str = list.get(1); 
    }
  • 泛型擦除 : 泛型只在編譯時(shí)期有效,編譯后的字節(jié)碼文件中不存在有泛型信息!
//泛型擦除實(shí)例
public void save(List<Person> p){
}
public void save(List<Dept> d){    // 報(bào)錯(cuò): 與上面方法編譯后一樣
}
  • 泛型寫法:
// 泛型寫法
    @Test
    public void testGeneric3() throws Exception {
        // 聲明泛型集合,集合兩端類型必須一致
        List<Object> list = new ArrayList<Object>();
        List<String> list1 = new ArrayList<String>();
        List list2 = new ArrayList<String>();
        List<Integer> list3 = new ArrayList();
        
        // 錯(cuò)誤
        //List<Object> list4 = new ArrayList<String>();
        // 錯(cuò)誤: 泛型類型必須是引用類型,不能為基本類型
        List<int> list5 = new ArrayList<int>();
    }
  • 泛型方法 / 泛型類 / 泛型接口 :
    • 作用 :
      a> 設(shè)計(jì)公用的類、方法,對公用的業(yè)務(wù)實(shí)現(xiàn)進(jìn)行抽取!
      b> 使程序更靈活!
    • 泛型方法 :
public class GenericDemo {
    // 定義泛型方法
    public <K,T> T save(T t,K k) {
        return null;
    }

    // 測試方法
    @Test
    public void testMethod() throws Exception {
        // 使用泛型方法:  在使用泛型方法的時(shí)候,確定泛型類型
        save(1.0f, 1);
    }
}
  • 泛型類 :
public class GenericDemo<T> {

    // 定義泛型方法
    public <K> T save(T t,K k) {
        return null;
    }
    
    public void update(T t) {

    }
    
    // 測試方法
    @Test
    public void testMethod() throws Exception {
        
        // 泛型類:  在創(chuàng)建愛泛型類對象的時(shí)候,確定類型
        GenericDemo<String> demo = new GenericDemo<String>();
        demo.save("test", 1);
    }
}
  • 泛型接口 :
// 泛型接口
public interface IBaseDao<T> {
    void save(T t );
    void update(T t );
}
  • 泛型接口類型確定 :
    a> 實(shí)現(xiàn)泛型接口的類也是抽象,那么類型在具體的實(shí)現(xiàn)中確定或創(chuàng)建泛型類的時(shí)候確定 : public class BaseDao<T> implements IBaseDao<T> {}
    b> 泛型接口類型確定: 在業(yè)務(wù)實(shí)現(xiàn)類中直接確定接口的類型 : public class PersonDao implements IBaseDao<Person>{}

  • 泛型關(guān)鍵字

    • ? : 指定只是接收值
//泛型, 涉及到一些關(guān)鍵字 
// Ctrl + shift + R   查看當(dāng)前項(xiàng)目中類
// Ctrl + shift + T   查看源碼jar包中的類
public class App_extends_super {
        //只帶泛型特征的方法
        public void save(List<?> list) {
                // 只能獲取、迭代list;  不能編輯list
        }

        @Test
        public void testGeneric() throws Exception {
                // ?  可以接收任何泛型集合, 但是不能編輯集合值; 所以一般在方法參數(shù)中用
                List<?> list = new ArrayList<String>();
                //list.add("");// 報(bào)錯(cuò)
        }
}
  • extends : 元素的類型必須繼承自指定的類
public class App_extends_super {
    /**
     * list集合只能處理 Double/Float/Integer等類型
     * 限定元素范圍:元素的類型要繼承自Number類  (上限)
     * @param list
     */
        public void save(List<? extends Number> list) {
        }

        @Test
        public void testGeneric() throws Exception {
                List<Double> list_1 = new ArrayList<Double>();
                List<Float> list_2 = new ArrayList<Float>();
                List<Integer> list_3 = new ArrayList<Integer>();
        
                List<String> list_4 = new ArrayList<String>();
        
                // 調(diào)用
                save(list_1);
                save(list_2);
                save(list_3);
                //save(list_4);
        }
}
  • super : 元素的類型必須是指定的類的父類
public class App_super {
    /**
     * super限定元素范圍:必須是String父類   【下限】
     * @param list
     */
        public void save(List<? super String> list) {
        }

        @Test
        public void testGeneric() throws Exception {
                // 調(diào)用上面方法,必須傳入String的父類
                List<Object> list1 = new ArrayList<Object>();
                List<String> list2 = new ArrayList<String>();
        
                List<Integer> list3 = new ArrayList<Integer>();
                //save(list3);
        }
}
  • 泛型的反射
// 所有dao的公用的方法,都在這里實(shí)現(xiàn)
public class BaseDao<T>{

    // 保存當(dāng)前運(yùn)行類的參數(shù)化類型中的實(shí)際的類型
    private Class clazz;
    // 表名
    private String tableName;
    // 構(gòu)造函數(shù): 1. 獲取當(dāng)前運(yùn)行類的參數(shù)化類型; 2. 獲取參數(shù)化類型中實(shí)際類型的定義(class)
    public BaseDao(){
        //  this  表示當(dāng)前運(yùn)行類  (AccountDao/AdminDao)
        //  this.getClass()  當(dāng)前運(yùn)行類的字節(jié)碼(AccountDao.class/AdminDao.class)
        //  this.getClass().getGenericSuperclass();  當(dāng)前運(yùn)行類的父類,即為BaseDao<Account>
        //                                           其實(shí)就是“參數(shù)化類型”, ParameterizedType   
        Type type = this.getClass().getGenericSuperclass();
        // 強(qiáng)制轉(zhuǎn)換為“參數(shù)化類型”  【BaseDao<Account>】
        ParameterizedType pt = (ParameterizedType) type;
        // 獲取參數(shù)化類型中,實(shí)際類型的定義  【new Type[]{Account.class}】
        Type types[] =  pt.getActualTypeArguments();
        // 獲取數(shù)據(jù)的第一個(gè)元素:Accout.class
        clazz = (Class) types[0];
        // 表名  (與類名一樣,只要獲取類名就可以)
        tableName = clazz.getSimpleName();
    }
    // 主鍵查詢
    public T findById(int id){
        /*
         * 1. 知道封裝的對象的類型
         * 2. 表名【表名與對象名稱一樣, 且主鍵都為id】
         * 
         * 即,
         *    ---》得到當(dāng)前運(yùn)行類繼承的父類  BaseDao<Account>
         *   ----》 得到Account.class
         */
        
        String sql = "select * from " + tableName + " where id=? ";
        try {
            return JdbcUtils.getQuerrRunner().query(sql, new BeanHandler<T>(clazz), id);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 查詢?nèi)?     * @return
     */
    public List<T> getAll(){
        String sql = "select * from " + tableName ;
        try {
            return JdbcUtils.getQuerrRunner().query(sql, new BeanListHandler<T>(clazz));
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }
}

反射復(fù)習(xí)

  • 反射,可以在運(yùn)行時(shí)期動(dòng)態(tài)創(chuàng)建對象;獲取對象的屬性、方法;
  • 反射技術(shù)實(shí)例 :
// 反射技術(shù)
public class App {

    // 1. 創(chuàng)建對象
    @Test
    public void testInfo() throws Exception {
        // 類全名
        String className = "cn.itcast.c_reflect.Admin";
        // 得到類字節(jié)碼
        Class<?> clazz = Class.forName(className);
        
        // 創(chuàng)建對象1: 默認(rèn)構(gòu)造函數(shù)簡寫
        //Admin admin = (Admin) clazz.newInstance();
        
        // 創(chuàng)建對象2: 通過帶參數(shù)構(gòu)造器創(chuàng)建對象
        Constructor<?> constructor = clazz.getDeclaredConstructor(String.class);
        Admin admin = (Admin) constructor.newInstance("Jack");
        
    }
    @Test
    //2. 獲取屬性名稱、值
    public void testField() throws Exception {
        
        // 類全名
        String className = "cn.itcast.c_reflect.Admin";
        // 得到類字節(jié)碼
        Class<?> clazz = Class.forName(className);
        // 對象
        Admin admin =  (Admin) clazz.newInstance();
        
        // 獲取所有的屬性名稱
        Field[]  fs =  clazz.getDeclaredFields();
        // 遍歷:輸出每一個(gè)屬性名稱、值
        for (Field f : fs) {
            // 設(shè)置強(qiáng)制訪問
            f.setAccessible(true);
            // 名稱
            String name = f.getName();
            // 值
            Object value = f.get(admin);
            
            System.out.println(name + value);
        }
    }
    
    @Test
    //3. 反射獲取方法
    public void testMethod() throws Exception {
        
        // 類全名
        String className = "cn.itcast.c_reflect.Admin";
        // 得到類字節(jié)碼
        Class<?> clazz = Class.forName(className);
        // 對象
        Admin admin =  (Admin) clazz.newInstance();
        
        // 獲取方法對象    public int getId() {
        Method m = clazz.getDeclaredMethod("getId");
        // 調(diào)用方法
        Object r_value = m.invoke(admin);
        
        System.out.println(r_value);
    }   
}

注解

  • 概述
    • 注解與注釋 :
      • 注解 : 告訴編譯器如何運(yùn)行程序!
      • 注釋 : 給程序員閱讀,對編譯、運(yùn)行沒有影響;
    • 注解的作用 :
      1. 告訴編譯器如何運(yùn)行程序;
      2. 簡化(取代)配置文件 【案例后再看】
    • 常用的注解 :
// 重寫父類的方法
    @Override
    public String toString() {
        return super.toString();
    }
    
    // 抑制編譯器警告
    @SuppressWarnings({"unused","unchecked"})
    private void save() {
        List list = null;
    }
    
    // 標(biāo)記方法以及過時(shí)
    @Deprecated
    private void save1() {
    }
  • 自定義注解
    a. 注解基本寫法
/**
 * 自定義注解  (描述一個(gè)作者)
 *
 */
public @interface Author {

    /**
     * 注解屬性
     *    1. 修飾為默認(rèn)或public
     *    2. 不能有主體
     */
    String name();
    int age();
}
// 使用
@Author(name = "Jet", age = 30)
    public void save() {

    }

b. 帶默認(rèn)值的注解

public @interface Author {
    /**
     * 注解屬性
     *   1. 修飾為默認(rèn)或public
     *   2. 不能有主體
     */
    String name();
    int age() default 30;   // 帶默認(rèn)值的注解;  使用的時(shí)候就可以不寫此屬性值
}

c. 默認(rèn)名稱的注解

public @interface Author {
    // 如果注解名稱為value,使用時(shí)候可以省略名稱,直接給值
    // (且注解只有一個(gè)屬性時(shí)候才可以省略名稱)
    String value();
}
// 使用
@Author("Jet")
@Author(value = "Jet")
//注解屬性類型為數(shù)組
public @interface Author {
    String[] value() default {"test1","test2"};
}
// 使用:
@Author({“”,“”})
public void save() {
}
  • 元注解
    • 元注解 : 表示注解的注解;
      • 可以指定注解的可用范圍, 例 : @Target({TYPE})
        a> TYPE->類
        b> FIELD->字段
        c> METHOD->方法
        d> PARAMETER->參數(shù)
        e> CONSTRUCTOR->構(gòu)造器
        f> LOCAL_VARIABLE->局部變量
      • 指定注解的聲明周期, 例 : @Retention(RetentionPolicy.SOURCE)
        • @Retention(RetentionPolicy.SOURCE) : 注解只在源碼級別有效
        • @Retention(RetentionPolicy.CLASS) : 注解在字節(jié)碼即別有效 默認(rèn)值
        • @Retention(RetentionPolicy.RUNTIME) : 注解在運(yùn)行時(shí)期有效
  • 注解反射
@Id
    @Author(remark = "保存信息!!!", age = 19)
    public void save() throws Exception {
        // 獲取注解信息: name/age/remark

        // 1. 先獲取代表方法的Method類型;
        Class clazz = App_2.class;
        Method m = clazz.getMethod("save");
        
        // 2. 再獲取方法上的注解
        Author author = m.getAnnotation(Author.class);
        // 獲取輸出注解信息
        System.out.println(author.authorName());
        System.out.println(author.age());
        System.out.println(author.remark());
    }

Log4J日志組件

  • 程序中為什么用日志組件?簡單來說,為了項(xiàng)目后期部署上線后的維護(hù)、錯(cuò)誤排查!Log4j, log for java, 開源的日志組件!
  • 使用步驟:
    1. 下載組件,引入jar文件 : log4j-1.2.11.jar
    2. 配置 : src/log4j.properties
    3. 使用
  • code :
# 通過根元素指定日志輸出的級別、目的地: 
#  日志輸出優(yōu)先級: debug < info < warn < error 
log4j.rootLogger=info,console,file
############# 日志輸出到控制臺 #############
# 日志輸出到控制臺使用的api類
log4j.appender.console=org.apache.log4j.ConsoleAppender
# 指定日志輸出的格式: 靈活的格式
log4j.appender.console.layout=org.apache.log4j.PatternLayout
# 具體格式內(nèi)容
log4j.appender.console.layout.ConversionPattern=%d %p %c.%M()-%m%n
############# 日志輸出到文件 #############
log4j.appender.file=org.apache.log4j.RollingFileAppender
# 文件參數(shù): 指定日志文件路徑
log4j.appender.file.File=../logs/MyLog.log
# 文件參數(shù): 指定日志文件最大大小
log4j.appender.file.MaxFileSize=5kb
# 文件參數(shù): 指定產(chǎn)生日志文件的最大數(shù)目
log4j.appender.file.MaxBackupIndex=100
# 日志格式
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern=%d %c.%M()-%m%n
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,182評論 6 543
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,489評論 3 429
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,290評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,776評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,510評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,866評論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,860評論 3 447
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,036評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,585評論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,331評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,536評論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,058評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,754評論 3 349
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,154評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,469評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,273評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,505評論 2 379

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,826評論 18 139
  • 主要內(nèi)容: 泛型 注解 動(dòng)態(tài)代理 類加載器 一、泛型 1.1 泛型(Generic)的作用 jdk5以前,對象保存...
    yjaal閱讀 768評論 0 6
  • 什么是注解(Annotation):Annotation(注解)就是Java提供了一種元程序中的元素關(guān)聯(lián)任何信息和...
    九尾喵的薛定諤閱讀 3,206評論 0 2
  • 多態(tài) 任何域的訪問操作都將有編譯器解析,如果某個(gè)方法是靜態(tài)的,它的行為就不具有多態(tài)性 java默認(rèn)對象的銷毀順序與...
    yueyue_projects閱讀 971評論 0 1
  • 我還是會(huì)想起你,破碎的時(shí)光里橫陳著的記憶 ——題記 昨夜居然夢見了你,我醒來之時(shí)關(guān)于你的回...
    攝影師酒黎閱讀 483評論 0 3