天天看點

java基礎之注解、自定義注解、解析注解

注解的初步了解

  • Annotation

    是從JDK5.0開始引入的新技術
  • Annotation

    作用
    • 注解不是程式本身,可以對程式作出解釋。(這一點和注釋沒有什麼差別)
    • 注解可以被其他程式(比如:編譯器等)讀取。(注解資訊處理流程,是注解和注釋的重大差別。如果沒有注解資訊處理流程,則注解毫無意義)
  • Annotation

    的格式
    • 注解是以"@注釋名"在代碼中存在的,還可以添加一些參數值,例如

      @SuppressWarnings(value = "unchecked")

  • Annotation

    在哪裡使用?
    • 可以附加在

      package

      class

      method

      field

      等上面,相當于給他們添加了額外的輔助資訊,我們可以通過反射機制程式設計實作對源資料的通路。

一些内置注解

  • @Override

定義在

java.lang.Override

中,此注解用于修飾一個方法,表示一個方法聲明打算重寫超類中的另一個方法聲明。

例如重寫

Object

類中的

toString()

方法

java基礎之注解、自定義注解、解析注解

如果

@Override

标注的方法不是父類的方法,就會報錯

java基礎之注解、自定義注解、解析注解
  • @Deprecated

定義在

java.lang.Deprecated

中,此注釋可用于修飾方法、屬性、類,表示不鼓勵程式員使用這樣的元素,通常是因為它很危險或存在更好的選擇

java基礎之注解、自定義注解、解析注解
  • @SupprerssWarnings

定義在

java.lang.SupressWarnings

中,用來抑制編譯器的警告資訊,此注解需要加上參數之後才能正常使用,參數清單如下:

參數 說明
deprecation 使用了過時的類或方法的警告
unchecked 執行了未檢查的轉換時的警告,如使用集合時未指定泛型
fallthrough 當switch語句使用時發生case穿透
path 在路徑、源檔案路徑等中有不存在路徑的警告
serial 當在序列化的類上缺少serialVersionUID定義時的警告
finally 任何finally子句不能完成的警告
all 關于以上所有情況的警告
@SuppressWarnings("uncheck")
// 多個參數的時候以數組的形式傳遞
@SuppressWarnings(value = {"unchecked","deprecation"})
           

自定義注解

元注解
  • 在自定義注解的時候,要在注解的定義上面加上幾個元注解
  • @Target

    • 作用:用于描述注解的使用範圍(即:被描述的注解可以用在什麼地方)
所修飾的範圍 取值

ElementType

package

PACKAGE

類、接口、枚舉、

Annotation

類型

TYPE

類型成員(方法、構造方法、成員變量、枚舉值)

CONSTRUCTOR

:用來描述構造器

FIELD

:用于描述域

METHOD

:用于描述方法
方法參數和本地變量

LOCAL_VARIABLE

:用于描述局部變量

PARAMETER

:用于描述參數

例如:

public class AnnotationTest {
    @MyAnnotation
    private void print(){
        System.out.println("AnnotationTest.print");
    }
}

@Target(ElementType.METHOD)
@interface MyAnnotation{
}
           

檢視

@Target

注解的源代碼

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}
           

可以發現它的參數是一個數組,是以我們可以定義多個

ElementType

,如下

@MyAnnotation
public class AnnotationTest {
    @MyAnnotation
    private void print(){
        System.out.println("AnnotationTest.print");
    }
}

@Target(value = {ElementType.METHOD,ElementType.TYPE})
@interface MyAnnotation{
}
           
  • @Retention

    • 作用:表示需要在什麼級别儲存該注解資訊,用于描述注解生命周期
取值

RetentionPolicy

作用

SOURCE

在源檔案中有效(即源檔案保留)

CLASS

在class檔案中有效(即class保留)

RUNTIME

在運作時有效(即運作時保留)為Runtime可以被反射讀取
自定義注解一般用RUNTIME
  • @Document

    • 表示将注解包含在Javadoc中
  • @Inherited

    • 表示允許子類繼承父類中的注解
參數
  • 自定義注解的參數在注解體内定義,可以設定預設值,格式如下
@MyAnnotation
public class AnnotationTest {
    @MyAnnotation(name = "小李", info = {"info1", "info2"})
    private void print() {
        System.out.println("AnnotationTest.print");
    }
}

@Target(value = {ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
    int type() default 0;

    String name() default "匿名使用者";

    String[] info() default {};
}
           
注意:當注解中隻有一個參數的時候,通常将參數名定義為

value

,并且在指派的時候可以省略參數名
@MyAnnotation2("demo")
public class AnnotationTest2 {
}

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation2{
    String value();
}
           
利用反射解析自定義注解
  • 需求:實作與Spring Data Jpa相似的功能,将一個實體類轉化為資料庫中一張表,需要解析出實體類對應的表名、字段名,然後用JDBC建立表。這裡隻用此例子解釋解析注解的原理,不深入探究Spring Data Jpa的底層實作
  • 自定義注解

    Table

package com.qianyu.mianshiti.annotation;

import java.lang.annotation.*;

/**
 * @author lijing
 * @date 2019-09-28 11:44
 * @description 表名
 */
@Target(ElementType.TYPE)
// 隻有RetentionPolicy.RUNTIME類型才能用反射解析
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
    // 對應表名
    String value();
}
           
  • 自定義注解

    Column

package com.qianyu.mianshiti.annotation;

import java.lang.annotation.*;

/**
 * @author lijing
 * @date 2019-09-28 11:48
 * @description 列名
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
    String name();

    boolean unique() default false;

    boolean nullable() default true;
}
           
  • 實體類
package com.qianyu.mianshiti.annotation;

/**
 * @author lijing
 * @date 2019-09-28 11:42
 * @description 對應t_user表
 */
@Table("t_user")
public class User {
    @Column(name = "u_id", unique = true, nullable = false)
    private Integer id;
    @Column(name = "u_name")
    private String name;
    @Column(name = "u_age")
    private Integer age;
}
           
  • 解析注解
package com.qianyu.mianshiti.annotation;

import java.lang.annotation.*;
import java.lang.reflect.*;

/**
 * @author lijing
 * @date 2019-09-28 11:54
 * @description 解析annotation
 */
public class Demo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
        Class clazz = Class.forName("com.qianyu.mianshiti.annotation.User");
        Annotation[] annotations = clazz.getAnnotations();
        // 擷取類上所有注解
        for (Annotation annotation : annotations) {
            System.out.println(annotation);
        }
        // 根據注解名擷取類注解
        Table table = (Table)clazz.getAnnotation(Table.class);
        System.out.println(table.value());
        // 根據注解名擷取屬性的注解
        Field id = clazz.getDeclaredField("id");
        Column column = id.getAnnotation(Column.class);
        System.out.println(column.name());
        System.out.println(column.unique());
        System.out.println(column.nullable());
        /**
         * 拼接SQL,使用JDBC操作資料庫.....
         */
    }
}
           
  • 運作結果:
java基礎之注解、自定義注解、解析注解