Java注解概述及自定義注解全面分析

一、 前言

我們大家都知道Java代碼中使用注釋是為了向以后閱讀這份代碼的人解釋說(shuō)明一些事情恢氯,注解是注釋的升級(jí)版带斑,它可以向編譯器、虛擬機(jī)等解釋說(shuō)明一些事情勋拟。比如我們非常熟悉的@Override就是一種元注解勋磕,它的作用是告訴編譯器它所注解的方法是重寫(xiě)父類(lèi)的方法,這樣編譯器就會(huì)去檢查父類(lèi)是否存在這個(gè)方法敢靡,以及這個(gè)方法的簽名與父類(lèi)是否相同挂滓。
我們?yōu)槭裁磳W(xué)習(xí)注解?學(xué)習(xí)注解有什么好處啸胧?學(xué)完能做什么赶站?
(1)、能夠讀懂別人的代碼纺念,特別是框架相關(guān)的代碼贝椿。
(2)、讓編程更加簡(jiǎn)潔陷谱,代碼更加清晰烙博。
(3)、讓別人高看一眼。

二习勤、 Java中的常見(jiàn)注解

1、JDK自帶注解@Override焙格、@Deprecated图毕、@Suppvisewarnings

(1)、@Override

定義

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

從這個(gè)注解類(lèi)的定義我們可以看到眷唉,這個(gè)注解可以被用來(lái)修飾方法予颤,并且它只在源碼時(shí)有效,在編譯后的class文件中便不存在冬阳。
這個(gè)注解的主要作用是告訴編譯器被修飾的方法是重寫(xiě)的父類(lèi)中的相同簽名的方法蛤虐,編譯器會(huì)對(duì)此做出檢查,若發(fā)現(xiàn)父類(lèi)中不存在這個(gè)方法或是存在的方法簽名不同肝陪,則會(huì)報(bào)錯(cuò)驳庭。

(2)、@Deprecated

定義

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

從它的定義我們可以知道氯窍,它會(huì)被文檔化饲常,能夠保留到運(yùn)行時(shí),能夠修飾構(gòu)造方法狼讨、屬性贝淤、局部變量、方法政供、包播聪、參數(shù)、類(lèi)或接口布隔。
這個(gè)注解的作用是告訴編譯器被修飾的程序元素已被“廢棄”离陶,不再建議用戶使用。

(3)衅檀、@Suppvisewarnings

定義

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
 String[] value();
}

它能夠修飾的程序元素包括類(lèi)或接口枕磁、屬性、方法术吝、參數(shù)计济、構(gòu)造器、局部變量排苍,只能存活在源碼時(shí)沦寂,取值為String[]。它的作用是告訴編譯器忽略指定的警告信息淘衙,它可以取的值如下所示:
deprecation:忽略使用了廢棄的類(lèi)或方法時(shí)的警告传藏;
unchecked:執(zhí)行了未檢查的轉(zhuǎn)換
fallthrough:swich語(yǔ)句款中case忘加break從而直接“落入”下一個(gè)case;
path:類(lèi)路徑或原文件路徑等不存在;
all:以上所有情況產(chǎn)生的警告均忽略毯侦。

(4)哭靖、實(shí)際使用介紹

自定義一個(gè)接口

/**
 * 動(dòng)物類(lèi)接口
 */
public interface Animal {
 public void eat();
 public void sleep();
 public void speak();
 public void sing();
}

定義Dog類(lèi)實(shí)現(xiàn)Animal接口

/**
 * 狗的實(shí)現(xiàn)類(lèi)
 *
 * @author YUBIN
 */
public class Dog implements Animal {
 @Override
 public void eat() {
 }
 @Override
 public void sleep() {
 }
 @Override
 public void speak() {
 }
 @Override
 public void sing() {
 }
}

此時(shí)你們?cè)贒og類(lèi)上的方法中看到@Override注解,表示該方法是重寫(xiě)或?qū)崿F(xiàn)父類(lèi)或接口的方法侈离,如果此時(shí)你在Dog類(lèi)中再書(shū)寫(xiě)一個(gè)接口中不存在的方法時(shí)试幽,然后在方法上使用@Override注解,則編譯檢查會(huì)報(bào)錯(cuò)卦碾,如下圖


image.png

我們仔細(xì)分析Animal這個(gè)接口铺坞,可以發(fā)現(xiàn)sing這個(gè)唱歌方法并不適用于所有的動(dòng)物,我們應(yīng)該把它去除洲胖,但是可能已經(jīng)有人使用了我們的這個(gè)接口济榨,這時(shí)我們應(yīng)該使用@Deprecated注解來(lái)告知?jiǎng)e人該方法已經(jīng)過(guò)時(shí)了。


image.png

效果:
image.png

但是這樣會(huì)導(dǎo)致代碼中出現(xiàn)警告圖標(biāo)绿映,對(duì)于有要求的公司來(lái)說(shuō)擒滑,是需要去除警告的,可以使用@SuppressWarnings("deprecation")來(lái)去除這個(gè)警告,這樣一來(lái)這個(gè)警告就消失了


image.png

三叉弦、 注解分類(lèi)

1橘忱、按照運(yùn)行機(jī)制分

(1)、源碼注解:注解只在源碼中存在卸奉,編譯成.class文件就不存在了栈幸。
(2)谨胞、編譯時(shí)注解:注解在源碼和.class文件中都存在末贾。
(3)筐钟、在運(yùn)行階段還起作用,甚至?xí)绊戇\(yùn)行邏輯的注解疹鳄。

元注解:注解的注解叫做元注解

四拧略、 自定義注解

1、自定義注解分語(yǔ)法要求

(1)瘪弓、使用@interface關(guān)鍵字定義注解
(2)垫蛆、成員以無(wú)參數(shù)無(wú)異常方式聲明
(3)、可以使用default為成員指定默認(rèn)值
(4)腺怯、成員類(lèi)型是受限的袱饭,合法的類(lèi)型包括基本數(shù)據(jù)類(lèi)型及String、Class呛占、Annotation虑乖、Enumeration
(5)、如果注解只有一個(gè)成員晾虑,則成員建議取名為value()疹味,在使用的時(shí)可以忽略成員名和賦值號(hào)(=)

2仅叫、注解的作用域

使用@Target來(lái)指明注解的作用域,表示該注解可以使用在什么地方糙捺,如下圖


image.png

CONSTRUCATOR:構(gòu)造方法聲明
FIELD:字段聲明
LOCAL_VARIABLE:局部變量聲明
METHOD:方法聲明
PACKAGE:包聲明
PARAMETER:參數(shù)聲明
TYPE:類(lèi)或接口

3诫咱、注解的生命周期

使用@Retention來(lái)指明定義的注解的生命周期


image.png

SOURCE:只在源碼中顯示,編譯時(shí)會(huì)丟棄
CLASS:編譯時(shí)會(huì)記錄到class中洪灯,運(yùn)行時(shí)忽略
RUNTIME:運(yùn)行時(shí)存在坎缭,可以通過(guò)反射讀取

4、@Inherited 允許子類(lèi)繼承

使用該注解婴渡,可以讓定義在父類(lèi)的注解被子類(lèi)所獲取,注意對(duì)接口無(wú)效凯亮。

5边臼、@Documented

生成javadoc時(shí)會(huì)包含注解


image.png

五、 解析注解

通過(guò)反射獲取類(lèi)假消、函數(shù)或成員上的運(yùn)行時(shí)注解信息柠并,從而實(shí)現(xiàn)動(dòng)態(tài)控制程序運(yùn)行的邏輯。在java.lang.redlect反射包中提供了一個(gè)接口AnnotatedElement富拗,該接口提供了獲取注解信息的幾個(gè)方法臼予,Class、Constructor啃沪、Field粘拾、Method、Package等都實(shí)現(xiàn)了該接口创千。

boolean isAnnotationPresent(Class<? extends Annotation> annotationClass); // 判斷指定元素上是否存在指定注解
<T extends Annotation> T getAnnotation(Class<T> annotationClass); // 獲取指定元素的指定注解
Annotation[] getAnnotations(); // 獲取指定元素上存在的注釋
Annotation[] getDeclaredAnnotations(); // 獲取指定元素上存在的直接注釋缰雇,非父類(lèi)的

運(yùn)行時(shí)注解解析案例:

public class Test {
  @SuppressWarnings("deprecation")
   public static void main(String[] args) {
   Class<BigDog> bigDogClass = BigDog.class;
   // 判斷類(lèi)上是否存在MyAnnotation注解
   boolean isExist = bigDogClass.isAnnotationPresent(MyAnnotation.class);
   if (isExist) {
     MyAnnotation annotation = bigDogClass.getAnnotation(MyAnnotation.class);
     System.out.println(annotation.desc());
   }
 }
}

六、 注解應(yīng)用實(shí)戰(zhàn)

下面我們以一個(gè)通過(guò)注解來(lái)實(shí)現(xiàn)生成sql為例追驴,來(lái)理解自定義注解的使用

1械哟、定義@Table注解

@Target(ElementType.TYPE) // 注解的作用范圍 作用在類(lèi)或接口上
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期 運(yùn)行時(shí)
public @interface Table {
 String value();
}

2、定義@Column注解

@Target(ElementType.FIELD) // 注解的作用范圍 作用在字段上
@Retention(RetentionPolicy.RUNTIME) // 注解的生命周期 運(yùn)行時(shí)
public @interface Column {
 String value(); // 只有一個(gè)成員,則定義成value,在使用的時(shí)候無(wú)參使用參數(shù)名和賦值符號(hào)=
}

3殿雪、定義實(shí)體類(lèi)

/**
 * 用戶的實(shí)體類(lèi)
 *
 * @author YUBIN
 */
@Table("tb_user")
public class User {

    @Column("id")
    private Long id;

    @Column("user_name")
    private String userName;

    @Column("sex")
    private Integer sex;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }
}

4暇咆、定義UserDao

/**
 * 用戶的持久層
 *
 * @author YUBIN
 */
public class UserDao {

    public String query(User user) {
        StringBuffer sb = new StringBuffer("select * from ");
        Class c = User.class;
        // 獲取類(lèi)上面的Table注解
        boolean isExistTableName = c.isAnnotationPresent(Table.class);
        if (!isExistTableName) {
            return null;
        }
        // 獲取表名
        Table table = (Table) c.getAnnotation(Table.class);
        sb.append(table.value()).append(" where 1=1");
        Field[] fields = c.getDeclaredFields();
        if (fields != null && fields.length > 0 && user != null) {
            for (Field field : fields) {
                // 獲取字段上的Column注解
                boolean isExistField = field.isAnnotationPresent(Column.class);
                if (isExistField) {
                    // 判斷該字段是否有值
                    // 獲取getXxx方法
                    String getMethodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                    try {
                        Method method = c.getMethod(getMethodName);
                        Object result = method.invoke(user, null);
                        if (result != null) {
                            Column column = field.getAnnotation(Column.class);
                            sb.append(" and " + column.value());
                            if (result instanceof String) {
                                sb.append("='").append(result).append("'");
                            } else {
                                sb.append("=").append(result);
                            }
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }

                }
            }
        }
        return sb.toString();
    }
}

5、測(cè)試類(lèi)

/**
 * 測(cè)試類(lèi)
 *
 * @author YUBIN
 */
public class Test {

    public static void main(String[] args) {
        UserDao userDao = new UserDao();
        User user = new User();
        user.setId(1L);
        user.setUserName("zhangsan");
        System.out.println(userDao.query(user));
    }
}

6丙曙、測(cè)試結(jié)果

image.png

七爸业、 結(jié)語(yǔ)

希望我的這篇文章能對(duì)大家理解注解、使用注解并且能夠自定義注解有所幫助亏镰,如有疑問(wèn)可在評(píng)論區(qū)交流沃呢,謝謝大家的支持。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末拆挥,一起剝皮案震驚了整個(gè)濱河市薄霜,隨后出現(xiàn)的幾起案子某抓,更是在濱河造成了極大的恐慌,老刑警劉巖惰瓜,帶你破解...
    沈念sama閱讀 218,036評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件否副,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡崎坊,警方通過(guò)查閱死者的電腦和手機(jī)备禀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)奈揍,“玉大人曲尸,你說(shuō)我怎么就攤上這事∧泻玻” “怎么了另患?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,411評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)蛾绎。 經(jīng)常有香客問(wèn)我昆箕,道長(zhǎng),這世上最難降的妖魔是什么租冠? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,622評(píng)論 1 293
  • 正文 為了忘掉前任鹏倘,我火速辦了婚禮,結(jié)果婚禮上顽爹,老公的妹妹穿的比我還像新娘纤泵。我一直安慰自己,他們只是感情好镜粤,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,661評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布夕吻。 她就那樣靜靜地躺著,像睡著了一般繁仁。 火紅的嫁衣襯著肌膚如雪涉馅。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,521評(píng)論 1 304
  • 那天黄虱,我揣著相機(jī)與錄音稚矿,去河邊找鬼。 笑死捻浦,一個(gè)胖子當(dāng)著我的面吹牛晤揣,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播朱灿,決...
    沈念sama閱讀 40,288評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼昧识,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了盗扒?” 一聲冷哼從身側(cè)響起跪楞,我...
    開(kāi)封第一講書(shū)人閱讀 39,200評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤缀去,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后甸祭,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體缕碎,經(jīng)...
    沈念sama閱讀 45,644評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,837評(píng)論 3 336
  • 正文 我和宋清朗相戀三年池户,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了咏雌。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,953評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡校焦,死狀恐怖赊抖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情寨典,我是刑警寧澤氛雪,帶...
    沈念sama閱讀 35,673評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站凝赛,受9級(jí)特大地震影響注暗,放射性物質(zhì)發(fā)生泄漏坛缕。R本人自食惡果不足惜墓猎,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,281評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望赚楚。 院中可真熱鬧毙沾,春花似錦、人聲如沸宠页。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,889評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)举户。三九已至烤宙,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間俭嘁,已是汗流浹背躺枕。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,011評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留供填,地道東北人拐云。 一個(gè)月前我還...
    沈念sama閱讀 48,119評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像近她,于是被迫代替她去往敵國(guó)和親叉瘩。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,901評(píng)論 2 355

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理粘捎,服務(wù)發(fā)現(xiàn)薇缅,斷路器危彩,智...
    卡卡羅2017閱讀 134,657評(píng)論 18 139
  • 本文章涉及代碼已放到github上annotation-study 1.Annotation為何而來(lái) What:A...
    zlcook閱讀 29,158評(píng)論 15 116
  • 什么是注解(Annotation):Annotation(注解)就是Java提供了一種元程序中的元素關(guān)聯(lián)任何信息和...
    九尾喵的薛定諤閱讀 3,166評(píng)論 0 2
  • さびしさや一尺消えてゆくほたる 流螢斷續(xù)光,一明一滅一尺間梧奢,寂寞何以堪狱掂。 轉(zhuǎn)瞬即逝的光芒比恒久的黑暗更讓人寂寞。 ...
    莫鷲一閱讀 3,378評(píng)論 0 1
  • 7月14日亲轨,我們的第一次義診活動(dòng)正式起航趋惨。此次活動(dòng),面向的是霓峪街道的父老鄉(xiāng)親們惦蚊,學(xué)校里所學(xué)的技能終于可以施展給本...
    合紙鳶閱讀 307評(píng)論 0 0