Java 基礎(chǔ) - 注解

  • 注解是一種在原程序中的元素關(guān)聯(lián)任何信息和任何元數(shù)據(jù)的途徑和方法。
  • 在 Java 項(xiàng)目中、尤其是框架相關(guān)的代碼,注解往往很常用,可以讓代碼更簡(jiǎn)潔清晰。

常見注解

JDK 自帶注解

  • @Override:覆蓋父類、實(shí)現(xiàn)接口的方法;
  • @Deprecated:方法已過時(shí)(可以被覆蓋,但調(diào)用時(shí)會(huì)提示過時(shí));
  • @SuppressWarnings("deprecation"):忽略方法過時(shí)的提示;
  • ...

第三方注解

Spring 注解:

  • @Autowired
  • @Service
  • @Repository
  • @Controller
  • ...

Mybatis 注解:

  • @InsertProvider
  • @UpdateProvider
  • @Options
  • ...
傳統(tǒng)方法引入 DAO
使用注解引入 DAO

注解分類

按運(yùn)行機(jī)制分類:

  • 源碼注解:注解只在源碼中存在,編譯成 .class 文件就不存在了;
  • 編譯時(shí)注解:在源碼和 .class 文件中都存在;
  • 運(yùn)行時(shí)注解:在運(yùn)行階段還起作用,甚至?xí)绊戇\(yùn)行邏輯。

按來源分類:

  • JDK 自帶注解
  • 第三方(框架)注解
  • 自定義注解
  • 元注解

自定義注解

定義注解

// 元注解
@Target({ElementType.METHOD, ElementType.TYPE})     // 聲明注解適用范圍:構(gòu)造方法、字段、局部變量、方法、包、參數(shù)、類和接口等
@Retention(RetentionPolicy.RUNTIME)                 // 生命周期:SOURCE(只存在于源碼)、CLASS(記錄到 class 中,運(yùn)行時(shí)忽略)、RUNTIME(運(yùn)行時(shí)存在,可反射)
@Inherited                                          // 在父類上添加了注解允許子類繼承
@Documented                                         // 生成 JavaDoc 時(shí)包含注解信息
public @interface Description {     // @interface 關(guān)鍵字定義注解

    // 注解可以沒有成員,沒有成員的注解稱為標(biāo)識(shí)注解
    // 如注解只有一個(gè)成員則必須取名為 value(),使用時(shí)可以忽略成員名和復(fù)制號(hào)(=)

    String desc();                  // 注解成員以無參無異常方式聲明

    String author();                // 成員類型受限:String、Class、Annotation、Enumeration

    int age() default 18;           // 可以為成員指定默認(rèn)值
}

使用自定義注解

@Desciption(desc="my test", author="YWH", age=17)
public String test() {
    return "OK";
}

解析注解

通過反射獲取類、方法或成員上的運(yùn)行時(shí)注解信息(只能是運(yùn)行時(shí)注解),從而實(shí)現(xiàn)動(dòng)態(tài)控制程序運(yùn)行的邏輯。

try {
    Class c = Class.forName("com.ywh.test.Test");
    boolean isExist = c.isAnnotationPresent(Description.class);    // 判斷類上是否添加了注解
    if (isExist) {
        Description d = c.getAnnotation(Description.class);
        System.out.println(d.value());
    }
    Method[] ms = c.getMethods();
    for (Method m: ms) {
        boolean isMExist = m.isAnnotationPresent(Description.class);
        if (isMExist) {
            Description d = (Description) m.getAnnotation(Description.class);
            System.out.println(d.value());
        }
    }
    // 另一種解析方法
    for(Method m: ms) {
        Annotation[] as = m.getAnnotations();
        for (Annotation a: as) {
            if (a instanceof Description) {
                Description d = (Description) a;
                System.out.println(d.value());
            }
        }
    }
}
catch (ClassNotFoundException e) {
    e.printStackTrace();
}

實(shí)例:使用注解實(shí)現(xiàn) ORM 框架(生成查詢語句)

Table.java

// 表注解
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    String value();
}

Column.java

// 字段注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String value();
}

定義測(cè)試數(shù)據(jù)模型

@Table("user")
public class Filter {

    @Column("id")
    private int id;

    @Column("user_name")
    private String name;

    public int getId() { return id; }

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

    public String getName() { return name; }

    public void setName(String name) { this.name = name; }
}

其對(duì)應(yīng)的 MySQL 表:

CREATE TABLE user (
    id INT,
    user_name VARCHAR(32)
);

Test.java

public class Test {

    public static void main(String[] args) {
        Filter f1 = new Filter();
        f1.setId(1);

        Filter f2 = new Filter();
        f2.setName("ywh");

        String sql1 = query(f1);
        String sql2 = query(f2);
        System.out.println(sql1);
        System.out.println(sql2);
    }


    private static String query(Filter f) {

        // 待拼裝的 SQL 語句
        StringBuilder sb = new StringBuilder();

        // 1. 獲取類類型,通過反射獲取類注解、從 Table 注解中提取出對(duì)應(yīng)的數(shù)據(jù)庫表名
        Class c = f.getClass();
        boolean exists = c.isAnnotationPresent(Table.class);
        if (!exists) {
            return null;
        }
        Table t = (Table) c.getAnnotation(Table.class);
        String tableName = t.value();

        sb.append("SELECT * FROM ").append(tableName).append(" WHERE 1 = 1");


        // 2. 遍歷數(shù)據(jù)模型類的所有字段(對(duì)應(yīng)數(shù)據(jù)庫表的字段),拼裝查詢條件
        Field[] fArray = c.getDeclaredFields();
        for (Field field : fArray) {

            // 2.1 獲取字段名:從 Column 注解中獲取字段對(duì)應(yīng)的數(shù)據(jù)庫字段名
            boolean fExists = field.isAnnotationPresent(Column.class);
            if (!fExists) {
                continue;
            }
            Column column = field.getAnnotation(Column.class);
            String columnName = column.value();

            // 2.2 獲取字段值:根據(jù)類的字段名拼裝出 getter 方法,求得字段值
            String fieldName = field.getName();
            String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
            Object fieldValue = null;
            try {
                Method getMethod = c.getMethod(getMethodName);
                fieldValue = getMethod.invoke(f);
            } catch (Exception e) {
                e.printStackTrace();
            }

            // 2.3 拼裝 SQL(暫不處理空值和等于 0 的值)
            if (fieldValue == null ||
                    (fieldValue instanceof Integer && (Integer) fieldValue == 0)
            ) {
                continue;
            }
            sb.append(" AND ").append(columnName);

            // 字段值為 String 類型
            if (fieldValue instanceof String) {

                // 以逗號(hào)割開,則解析為 IN 條件
                if (((String) fieldValue).contains(",")) {
                    String[] values = ((String) fieldValue).split(",");
                    sb.append(" IN (");
                    for (String v : values) {
                        sb.append("'").append(v).append("'").append(",");
                    }
                    sb.deleteCharAt(sb.length() - 1);       // 刪除最后一個(gè)逗號(hào)
                    sb.append(")");
                } else
                    sb.append(" = ").append("'").append(fieldValue).append("'");
            }
            // 字段值為其他類型
            else if (fieldValue instanceof Integer) {
                sb.append(" = ").append(fieldValue);
            }
        }

        return sb.toString();
    }

}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 夯實(shí) Java 基礎(chǔ) - 注解 不知道大家有沒有一種感覺,當(dāng)你想要了解某個(gè)知識(shí)點(diǎn)的時(shí)候,就會(huì)發(fā)現(xiàn)好多技術(shù)類 APP...
    醒著的碼者閱讀 1,136評(píng)論 4 7
  • 注解基本概念 我們?cè)陂_發(fā)當(dāng)中經(jīng)常看到一些注解,例如override,Deprected等,這些注解再常見不過了,但...
    zhonj閱讀 1,158評(píng)論 0 0
  • 回顧 3.構(gòu)造方法的私有化 六、在方法內(nèi)部調(diào)用方法 七、方法的遞歸調(diào)用 八、代碼塊 學(xué)習(xí)小結(jié) 八、代碼塊 1.普通...
    礫桫_Yvan閱讀 211評(píng)論 0 1
  • 你一把疏狂醉,你一盞清樽酒。把落寞書寫得淋漓盡致,把滄桑付予一聲嘆息。那么多的,難過,你不說。 從晉國(guó)公子享盡富貴...
    春余清歌閱讀 1,499評(píng)論 15 19
  • 臨摹的一副作品,都說這幅畫讓人看了內(nèi)心寧靜,不知道自己有沒有畫出那份感覺,在這炎熱的夏天,內(nèi)心很容易浮躁。我就...
    Jesy思思閱讀 245評(píng)論 21 14

友情鏈接更多精彩內(nèi)容