1. 程式人生 > >【java提高】(16)---java註解(Annotation)

【java提高】(16)---java註解(Annotation)

java提高(16)---java註解

註解含義註解是JDK1.5之後才有的新特性,它相當於一種標記,在程式中加入註解就等於為程式打上某種標記,之後又通過類的反射機制來解析註解。

一、JDK自帶註解

JDK1.5之後內部提供的三個註解

 @Deprecated       #廢棄,過時。
 @Override         #重寫、覆蓋。
 @SuppressWarnings #壓縮警告。

示例

@SuppressWarnings("deprecation")
public class AnnotationTest {
    //4、這裡稱為壓縮警告註解,可以在類上也可以放在方法上,因為該方法用了個已經過期的方法.getYear(),所以會發出警告
    //加上這個註解表明取消對deprecation的警告,那麼該方法裡有過時方法也不會發出預警。同時getYear()的那條橫線也消失了。
    @SuppressWarnings("deprecation")
    public static void main(String[] args) {

   //1、這裡的.getYear()方法畫了一條橫線表示此方法已經過時了,裡面方法加上了@Deprecated註解
        new Date().getYear();
    }

    //2、這裡我通過@Deprecated註解自定義一個已經過時不建議使用的方法。
    @Deprecated
    public String   getName() {
        return "小小";

    }
    //3、重寫(覆蓋)父類Object的toString()方法
    @Override
    public String toString() {
        return "小小";
    }
}

註解示意圖


二、自定義註解

示例

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface AnCode {//使用@interface關鍵字定義註解

    //如果只有一個屬性 強烈建議取名為value
    String value() default "";
}                                       

在自定義註解上面有四個註解,我們稱為元註解,下面一個一個解釋。

1、@Target 用於描述註解的使用範圍

取值(ElementType)有:
    1、CONSTRUCTOR:   用於描述構造器
    2、FIELD:         用於描述域(欄位申明)
    3、LOCAL_VARIABLE:用於描述區域性變數
    4、METHOD:        用於描述方法
    5、PACKAGE:       用於描述包
    6、PARAMETER:     用於描述引數
    7、TYPE:          用於描述類、介面(包括註解型別) 或enum宣告
    8、TYPE_PARAMETER:輸入引數申明(JDK1.8)
    9、TYPE_USE:      使用型別(JDK1.8)

2、@Retention 定義了該註解生命週期

取值(RetentionPoicy)有:
    1、SOURCE:  在原始檔中有效(即原始檔保留)
    2、CLASS:   在class檔案中有效(即class保留)
    3、RUNTIME: 註解永久保留,可以被VM載入時載入到記憶體中

一般框架註解和我們自定義註解採用的幾乎都是RUNTIME,因為只有這個才能執行時通過反射來獲取註解中的資料。

3、@Inherited

概念: @Inherited闡述了某個被標註的型別是被繼承的。如果一個使用了@Inherited修飾的annotation型別被用於一個class,則這個annotation將被用於該class的子類。

注意:@Inherited annotation型別是被標註過的class的子類所繼承。類並不從它所實現的介面繼承annotation,方法並不從它所過載的方法繼承annotation
解釋: 比如A繼承B,B類的上面有一個註解@A帶有元註解@Inherited 那麼A也可以擁有B父類的這個註解@A,但介面實現是不可以的。同時需要指出@A註解是需要元註解@Retention(RetentionPolicy.RUNTIME)。

參考文章:java @Inherited註解的作用

4、@Documented

概念:描述其它型別的annotation應該被作為被標註的程式成員的公共API,因此可以被例如javadoc此類的工具文件化。

5、自定義註解引數

  1、只能用public或預設(default)這兩個訪問權修飾.例如,String value();這裡把方法設為defaul預設型別;  
      2、引數成員只能用基本型別byte,short,char,int,long,float,double,boolean八種基本資料型別和
           String,Enum,Class,annotations等資料型別,以及這一些型別的陣列;
   3、如果只有一個引數成員,最好把引數名稱設為"value",後加小括號(也可以不加小括號)


三、自定義註解案例

目標 實現一個簡單的通過註解生成SQL查詢語句。

先建立兩個註解

@Table表名註解

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {

    //資料庫表名屬性
    String value() default "";
}

@Column欄位名註解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    //資料庫表字段名稱和實體屬性對映
    String value() default "";
}

User實體

@Table("t_user")
public class User {
    /**
     * 使用者Id
     */
    @Column("user_id")
    private Integer userId;
    /**
     * 使用者年齡
     */
    @Column("age")
    private Integer age;
    
    public User(Integer userId, Integer age) {
        this.userId = userId;
        this.age = age;
    }
    //新增get和set方法
    }

解析註解類

public class Query {
    public static String query(Object object) throws Exception{
        StringBuilder sql = new StringBuilder();
        //1.利用反射獲取Class
        Class c = object.getClass();
        //2.獲取Table的名字
        boolean isExist = c.isAnnotationPresent(Table.class);
        if (!isExist) {
            return null;
        }
        Table t = (Table) c.getAnnotation(Table.class);
        //3、獲取註解上的value值
        String tableName = t.value();
        sql.append("select * form ").append(tableName).append(" where 1 = 1 ");
        //4.遍歷所有的屬性欄位
        Field[] fArray = c.getDeclaredFields();
        for (Field field : fArray) {
            //處理每個欄位對應的sql
            boolean fExist = field.isAnnotationPresent(Column.class);
            if (!fExist) {
                continue;
            }
            Column column = field.getAnnotation(Column.class);
            //資料庫欄位名
            String columnName = column.value();
            //5、將user_id 變成 userId
            String[] columns = columnName.split("_");
            StringBuilder columnBuilder = new StringBuilder();
            for (int i = 0; i < columns.length; i++) {
                String s = columns[i];
                columnBuilder.append(s.substring(0, 1).toUpperCase()).append(s.substring(1));
            }
            //6、活動屬性值
            String getMethodName = "get" + columnBuilder.toString(); //get方法名
            Method getMethod = c.getMethod(getMethodName);
            Object  fieldValue = getMethod.invoke(object);//類欄位值
            //7、拼裝sql
            sql.append(" and ").append(columnName).append(" = ").append(fieldValue);
        }
        return sql.toString();
    }
}

測試類

public static void main(String[] args) throws Exception {
        User user = new User(001, 4);
        String query = Query.query(user);
        System.out.println("query = " + query);
    }

執行結果

通過這個小案例實現了通過註解的方式,生成sql語句。




只要自己變優秀了,其他的事情才會跟著好起來(少將20)