Java中標籤開發 | 註解實戰

這是我參與更文挑戰的第28天,活動詳情查看: 更文挑戰java

spring開源框架,裏面全是經過註解實現的spring

spring開源框架,裏面全是經過註解實現的,咱們使用在使用的時候也嚐到很多好處,因此就抽空看看Java給咱們提供的註解機制的使用。編程


什麼是註解

  • 註解就是相似於註釋同樣,起到對類、方法、字段等的說明做用。Annotation(註解)是在jdk1.5以後才引入的概念。因此你要想實現註解你的jdk必須1.5以上。他能夠用於建立文檔,跟蹤代碼的依賴性。甚至也能夠執行基本的編譯語法檢查。註解的格式是以@開頭的,@interface形式的類名申請。上面說了,註解你就能夠理解爲註釋,由於註解是不會影響到代碼的語義的。註解有三種存在方式,一種是存在源碼中,一種是在編譯中,一種是在運行期間有效。

註解的做用

  • 編寫文檔:經過代碼裏標識的元數據生成文檔。

  • 代碼分析:經過代碼裏標識的元數據對代碼進行分析。

  • 編譯檢查:經過代碼裏標識的元數據讓編譯器能實現基本的編譯檢查

基本註解

  • 在Java中咱們初學者可能不知道什麼是註解,可是咱們確定都是永富哦註解的,下面來看看咱們在哪裏用過他們吧,

Overridemarkdown

  • java.lang.Override是一個標記類型註解,它被用做標註方法.他說明了該方法是繼承了父類的方法,就是重寫了父類中同名方法。若是咱們在一個方法上面使用的@override,可是實際上父類根本沒有這個方法,就是說咱們這個方法沒有重載父類的方法。這個時候咱們在編譯時就會報相應的編譯錯誤。

SuppressWarningsapp

  • 我對這個註解的理解就是經過它告訴編譯器忽視我下面可能出現的警告。實際上裏面有不少參數,不一樣參數設置不一樣的警告
-  deprecation,使用了過期的類或方法時的警告
-  unchecked,執行了未檢查的轉換時的警告
-  fallthrough,當 switch 程序塊直接通往下一種狀況而沒有 break 時的警告
-  path,在類路徑、源文件路徑等中有不存在的路徑時的警告
-  serial,當在可序列化的類上缺乏serialVersionUID 定義時的警告
-  finally ,任何 finally 子句不能正常完成時的警告
-  all,關於以上全部狀況的警告
複製代碼

Deprecated框架

  • 這個註解我實際沒有接觸過,這個我在網上搜了一下,人家的解釋爲

它的做用是對不該該再使用的方法添加註解,當編程人員使用這些方法時,將會在編譯時顯示提示信息,它與javadoc裏的@deprecated標記有相同的功能,準確的說,它還不如javadoc @deprecated,由於它不支持參數,使用@Deprecated的示例代碼示例以下: 這裏寫圖片描述ide

  • 在咱們平時編寫代碼用到jdk中的方法,有的時候回遇到某個方法過期了,可是能夠用,那個方法就是經過這個註解實現的,簡單說就是提示開發者方法過期,儘可能避免使用過期方法。

jdk提供了開發註解的方法

  • 有了上面的介紹咱們多多少少對註解有了瞭解,既然Java已經有了註解的概念那麼咱們如何開發本身的註解呢。在java.lang.annotation這個包裏jdk放置了關於註解的註解,就是經過裏面的註解類咱們能夠開發本身的註解。下面先來認識一下註解的註解吧。

這裏寫圖片描述

  • 經過觀察源碼,其中annotation 、annotationFormatError、annotationTypeMismatchExcetion、IncompleteAnnotationException這四個類有事異常類又是基本類頁遊格式化的,這些類咱們開發註解時咱們不會遇到的,都是jdk裏邏輯。咱們真正使用的是剩下的幾個類。

ElementTypesvn

  • 這個類是個枚舉,這裏枚舉的字段就是給Target類中使用的。具體在Target中說明

RetentionPolicy函數

  • 這個類是個枚舉,這裏枚舉的字段就是給Retention類中使用的。具體在Retention中說明

Documented工具

/**
 * Indicates that annotations with a type are to be documented by javadoc
 * and similar tools by default.  This type should be used to annotate the
 * declarations of types whose annotations affect the use of annotated
 * elements by their clients.  If a type declaration is annotated with
 * Documented, its annotations become part of the public API
 * of the annotated elements.
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
複製代碼
  • 這是官網的jdk上對documented類的描述,這段描述的大體意思是該類的申明是用在生成Java文檔上的註解,也就是說這個註解上就能夠生成文檔說明,而且這個也是默認的實用工具。這種註解應該在客戶端上被注入。與此同時他們的方法也成爲公共的API.

Target

/**
 * Indicates the kinds of program element to which an annotation type
 * is applicable.  If a Target meta-annotation is not present on an
 * annotation type declaration, the declared type may be used on any
 * program element.  If such a meta-annotation is present, the compiler
 * will enforce the specified usage restriction.
 *
 * For example, this meta-annotation indicates that the declared type is
 * itself a meta-annotation type.  It can only be used on annotation type
 * declarations:
 * <pre>
 *    &#064;Target(ElementType.ANNOTATION_TYPE)
 *    public &#064;interface MetaAnnotationType {
 *        ...
 *    }
 * </pre>
 * This meta-annotation indicates that the declared type is intended solely
 * for use as a member type in complex annotation type declarations.  It
 * cannot be used to annotate anything directly:
 * <pre>
 *    &#064;Target({})
 *    public &#064;interface MemberType {
 *        ...
 *    }
 * </pre>
 * It is a compile-time error for a single ElementType constant to
 * appear more than once in a Target annotation.  For example, the
 * following meta-annotation is illegal:
 * <pre>
 *    &#064;Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
 *    public &#064;interface Bogus {
 *        ...
 *    }
 * </pre>
 */
複製代碼
  • 一樣上面仍然是Java JDK官網的說明,首先是說若是target指定的類型元素不存在的話,那麼經過target指定的註解將能夠用在任何地方,若是target指定元素,則該註解必須只能用在指定的元素上,target指定的元素是經過ElementType這個枚舉類指定的,裏面的枚舉就是target能夠指定的值。官網上的列子是Target(ElementType.ANNOTATION_TYPE)代表這個註解只能用在註解本省上面。還有一種屬性不在ElementType枚舉中,就是target({}),就是經過{}的註解是用來在負責註解上的成員變量,他不能用在其餘的地方。

  • ElementType.CONSTRUCTOR:用於描述構造器

  • ElementType.FIELD:成員變量、對象、屬性(包括enum實例)

  • ElementType.LOCAL_VARIABLE:用於描述局部變量

  • ElementType.METHOD:用於描述方法

  • ElementType.PACKAGE:用於描述包

  • ElementType.PARAMETER:用於描述參數

  • ElementType.TYPE:用於描述類、接口(包括註解類型) 或enum聲明

Retention

/**
 * Indicates how long annotations with the annotated type are to
 * be retained.  If no Retention annotation is present on
 * an annotation type declaration, the retention policy defaults to
 * {@code RetentionPolicy.CLASS}.
 *
 * <p>A Retention meta-annotation has effect only if the
 * meta-annotated type is used directly for annotation.  It has no
 * effect if the meta-annotated type is used as a member type in
 * another annotation type.
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
複製代碼
  • 這個類的屬性是經過RetentionPolicy這個枚舉類列舉屬性的,這個主要的做用是指定咱們的註解存在的時間或者說是存在的時刻。這個屬性只有直接用在原註釋類型的註解上纔有效。若是用在其餘註解的成員變量上就沒有效果了。

  • RetentionPolicy.SOURCE : 在編譯階段丟棄。這些註解在編譯結束以後就再也不有任何意義,因此它們不會寫入字節碼。@Override, @SuppressWarnings都屬於這類註解。

  • RetentionPolicy.CLASS : 在類加載的時候丟棄。在字節碼文件的處理中有用。註解默認使用這種方式

- RetentionPolicy.RUNTIME : 始終不會丟棄,運行期也保留該註解,所以可使用反射機制讀取該註解的信息。咱們自定義的註解一般使用這種方式。
複製代碼

Inherited

/**
 * Indicates that an annotation type is automatically inherited.  If
 * an Inherited meta-annotation is present on an annotation type
 * declaration, and the user queries the annotation type on a class
 * declaration, and the class declaration has no annotation for this type,
 * then the class's superclass will automatically be queried for the
 * annotation type.  This process will be repeated until an annotation for this
 * type is found, or the top of the class hierarchy (Object)
 * is reached.  If no superclass has an annotation for this type, then
 * the query will indicate that the class in question has no such annotation.
 *
 * <p>Note that this meta-annotation type has no effect if the annotated
 * type is used to annotate anything other than a class.  Note also
 * that this meta-annotation only causes annotations to be inherited
 * from superclasses; annotations on implemented interfaces have no
 * effect.
 *
 * @author  Joshua Bloch
 * @since 1.5
 */
複製代碼
  • 一句話總結就是是否容許子類繼承該註解

自定義註解

  • 上面說了這麼多,那麼下面咱們開始開發本身的註解吧。

構造器註解

/**
 * 該註解用於doc文檔
 * 該註解用於類的構造函數的註解
 * 該註解盡在運行期間有效
 * @author xinhua
 *
 */
@Documented
@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
public @interface ConstructorAnno
{

    String decs() default "我是描述構造函數的註解";
}
複製代碼

字段註解

/**
 * 該註解用於生成doc文檔
 * 該註解用於在類的字段屬性上的註解
 * 該註解盡在運行期間有效
 * @author xinhua
 *
 */
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FieldAnno
{

    String desc() default "我是描述字段的註解";
}
複製代碼

局部變量註解

/**
 * 該註解用於生成doc文檔
 * 該註解用於在局部變量上的註解
 * 該註解盡在運行期間有效
 * @author xinhua
 *
 */
@Documented
@Target(ElementType.LOCAL_VARIABLE)
@Retention(RetentionPolicy.RUNTIME)
public @interface LocalAnno
{
    String desc() default "我是描述一個局部變量的註解";
}
複製代碼

方法註解

/**
 * 這個註解用於生成doc文檔
 * 這個註解用於類的方法上的註解
 * 這個註解盡在運行期間有效
 * @author xinhua
 *
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodAnno
{
    //默認提交時間  2017-2-28
    String time() default "2017-2-28";
    
    //默認  男    true 男  false 女 
    boolean sex() default true;
}
複製代碼

包註解

/**
 * 該註解用於生成doc文檔
 * 該註解用於在包的註解
 * 該註解盡在運行期間有效
 * @author xinhua
 *
 */
@Documented
@Target(ElementType.PACKAGE)
@Retention(RetentionPolicy.RUNTIME)
public @interface PackageAnno
{

    String desc() default "我是描述包的註解";
}

複製代碼

參數註解

/**
 * 該註解用於doc文檔的生成
 * 該註解用於類的參數中
 * 該註解盡在運行期間有效
 * @author xinhua
 *
 */
@Documented
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface StuInfo
{
    String value() default "";
}

複製代碼

類型註解

/**
 * 該註解用於生活曾doc文檔
 * 該註解用於在類的註解
 * 該註解盡在運行期間有效
 * @author xinhua
 *
 */
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TypeAnno
{

    String desc() default "我是描述類型的註解";
}
複製代碼

加入測試的實體類

/**
 * 測試全部類型的註解的做用
 * @author xinhua
 *
 */
public @TypeAnno(desc="我是普通類")class User
{
    @FieldAnno
    private String UID;
    
    @FieldAnno(desc="我是UserName的")
    private String userName;
    
    @ConstructorAnno
    public User(){
        
    }
    
    @MethodAnno(time="2015-12-8" , sex=false)
    public void doHomeWork(@StuInfo(value="211311084") String UID, @StuInfo(value="張新華")String UserName){
         @LocalAnno(desc="flag的局部變量")boolean flag;
         
    }
}
複製代碼

加入測試的接口類

public interface UserImp
{

    public void DoHouseWork(@StuInfo(value="我是小學生")String stuType,@StuInfo(value="我在大掃除")String things);
}
複製代碼

測試註解

/**
 * 開始經過反射獲取註解內容
 * @author xinhua
 *
 */
public class Junit
{

    public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException
    {
        Class<?> userClass = Class.forName("tom.change.annotation.User");
        //實例化
        Object userObject = userClass.newInstance();
        //1--獲取最外層的就是類的註解  TypeAnno
        System.out.println(".......................類註解.......................");
        TypeAnno typeAnno= userClass.getAnnotation(TypeAnno.class);
        System.out.println(typeAnno.desc());
        //2--獲取字段註解 首先獲取經過反射獲取類中的屬性字段
        System.out.println(".......................字段註解.......................");
        Field[] fields = userClass.getDeclaredFields();
        for (Field field : fields)
        {
            FieldAnno fieldAnno = field.getAnnotation(FieldAnno.class);
            System.out.println(fieldAnno.desc());
        }
        //3-- 方法的註解
        System.out.println(".......................方法註解.......................");
        Method method = userClass.getMethod("doHomeWork", String.class,String.class);
        MethodAnno methodAnno = method.getAnnotation(MethodAnno.class);
        System.out.println(methodAnno.time()+"@@@"+methodAnno.sex());
        
        //4-- 參數的註解  動態代理方式實現參數
        System.out.println(".......................參數註解.......................");
        UserImp userImp=getMethodParameter(UserImp.class);
        userImp.DoHouseWork("張新華", "--》掃地");
        
        //5--局部變量註解 
        System.out.println(".......................局部變量註解.......................");
        //贊未得到到
    }
    
    public static<T> T getMethodParameter(Class<T> target){
        return (T)Proxy.newProxyInstance(target.getClassLoader(), new Class<?>[]{target}, new InvocationHandler()
        {
            
            @Override
            public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable
            {
                Annotation[][] parameterAnnotations = method.getParameterAnnotations();
                for (int i=0;i<parameterAnnotations.length;i++)
                {
                    Annotation[] annotations=parameterAnnotations[i];
                    StuInfo stuInfo =(StuInfo) annotations[0];
                    System.out.println(stuInfo.value()+"@@@"+args[i]);
                }
                
                return null;
            }
        });
    }
}
複製代碼

效果圖

這裏寫圖片描述

相關文章
相關標籤/搜索