注解-Annotation Types学习

前言:注解是JDK5 之后推出的特性,可修饰包、类、方法、变量等,通过在编译、加载和运行时读取其信息,可执行相应的处理。

基本原理

java注解类型实质上是一个标记,如:

@Autowired
private TestBean testBean;

@Autowired标记了testBean这个域属性,这个标记的意义就是自动注入,告诉spring这个域属性需要注入该类型的对象。

通过反射机制,可以得到相应的注解,并对注解进行定制化处理,如@Deprecated 标记过期,@Override 标记重写函数。
注解本身有无,并不影响程序的编译如@Override,但可能会影响程序的正常运行,如@Autowired,若删掉该注解,则对应域属性没有实例化的bean,产生异常。

注解组成

注解由来
public interface Annotation {

    boolean equals(Object obj);

    int hashCode();

    String toString();

    Class<? extends Annotation> annotationType();
}

注解不是新的东西,也是需要通过java原生语言来定义,Annotation接口声明了注解的源头。在定义注解时,仅需要在定义接口时,在interface 前加 @ 即可定义成功。@interface 实际上继承了 java.lang.annotation.Annotation 表明自己为注解类型。

注:注解本身不能再被继承,且无法通过extends java.lang.annotation.Annotation 方式声明自己的注解类型

以@Override为例,对注解的定义进行讲解。@Override 表明该方法覆盖了其父类或接口的方法。其上又包含了@Target与@Retention两个注解。

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
  • @Target注解表明该注解可标注的位置,其内部接受一个ElementType类型的数组,ElementType类型如下:
public enum ElementType {

    /** 标明该注解可以用于类、接口(包括注解类型)或enum声明 */
    TYPE,
    /** 标明该注解可以用于字段(域)声明,包括enum实例 */
    FIELD,

    /** 标明该注解可以用于方法声明 */
    METHOD,

    /** 标明该注解可以用于参数声明 */
    PARAMETER,

    /** 标明注解可以用于构造函数声明 */
    CONSTRUCTOR,

    /** 标明注解可以用于局部变量声明 */
    LOCAL_VARIABLE,

    /** 标明注解可以用于注解声明(应用于另一个注解上)*/
    ANNOTATION_TYPE,

    /** 标明注解可以用于包声明 */
    PACKAGE,

    /**
     * 标明注解可以用于类型参数声明(1.8新加入)
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * 类型使用声明(1.8新加入)
     * @since 1.8
     */
    TYPE_USE
}
  • @Retention表明注解的生命周期,其接受RetentionPolicy枚举值,RetentionPolicy类型如下:
public enum RetentionPolicy {
    /**
     * 信息只保留在源码中,编译时将丢弃
     */
    SOURCE,

    /**
     * 信息只保留在源码和 编译后的class文件中,但加载到JVM时将被丢弃。
     */
    CLASS,

    /**
     * 信息将保留在源码、class文件以及运行时。
     */
    RUNTIME
}

再看这两个注解的定义:

@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();
}

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

可见这两个注解自身也被自身标记,并声明了自身的声明周期及作用对象。

@Target和@Retention注解中,包含了value()方法,并含有返回值。该方法表明了注解接受何种类型的属性值。如@Target接受ElementType类型的数组,该属性值将由该注解定义者来决定如何使用。

其中,注解内可定义多个方法,且多种返回类型,但由限制。

  • 对于方法,若有属性值且无默认值,则必须提供该属性的值,如@Target(ElementType.ANNOTATION_TYPE)或定义默认值。
value() default ElementType.ANNOTATION_TYPE

当注解内有唯一的方法,且方法名为value() 则,在使用时,无须通过key=value形式,直接赋值即可,如@Target(ElementType.ANNOTATION_TYPE),否则需要通过@Target(value=ElementType.ANNOTATION_TYPE)赋值。

  • 对于返回值,需要在以下类型范围内,且不能接受null值。
所有基本类型(int,float,boolean,byte,double,char,long,short)

String

Class

enum

Annotation

上述类型的数组

public @interface AnnotationElementDemo {
    //枚举类型
    enum Status {FIXED,NORMAL};

    //声明枚举
    Status status() default Status.FIXED;

    //布尔类型
    boolean showSupport() default false;

    //String类型
    String name()default "";

    //class类型
    Class<?> testCase() default Void.class;

    //注解嵌套
    Override reference();

    //数组类型
    long[] value();
}

注解信息使用
返回值方法名说明
<A extends Annotation>getAnnotation(Class<A>annotationClass)该元素如果存在指定类型的注解,则返回这些注解,否则返回 null。
Annotation[]getAnnotations()返回此元素上存在的所有注解,包括从父类继承的
booleanisAnnotationPresent(Class<? extends Annotation> annotationClass)如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。
Annotation[]getDeclaredAnnotations()返回直接存在于此元素上的所有注解,注意,不包括父类的注解,调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响,没有则返回长度为0的数组

简单实例:

package com.zejian.annotationdemo;

import java.lang.annotation.Annotation;
import java.util.Arrays;

/**
 * Created by zejian on 2017/5/20.
 * Blog : http://blog.csdn.net/javazejian [原文地址,请尊重原创]
 */
@DocumentA
class A{ }

//继承了A类
@DocumentB
public class DocumentDemo extends A{

    public static void main(String... args){

        Class<?> clazz = DocumentDemo.class;
        //根据指定注解类型获取该注解
        DocumentA documentA=clazz.getAnnotation(DocumentA.class);
        System.out.println("A:"+documentA);

        //获取该元素上的所有注解,包含从父类继承
        Annotation[] an= clazz.getAnnotations();
        System.out.println("an:"+ Arrays.toString(an));
        //获取该元素上的所有注解,但不包含继承!
        Annotation[] an2=clazz.getDeclaredAnnotations();
        System.out.println("an2:"+ Arrays.toString(an2));

        //判断注解DocumentA是否在该元素上
        boolean b=clazz.isAnnotationPresent(DocumentA.class);
        System.out.println("b:"+b);

        /**
         * 执行结果:
         A:@com.zejian.annotationdemo.DocumentA()
         an:[@com.zejian.annotationdemo.DocumentA(), @com.zejian.annotationdemo.DocumentB()]
         an2:@com.zejian.annotationdemo.DocumentB()
         b:true
         */
    }
}

Demo

@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @ interface PersonalName {
    String filedName() default "";

    String methodName() default "";

    String className() default "";
}


@PersonalName(className = "测试类")
public class TestBean {

    @PersonalName(filedName = "我的名字")
    public String myName= "";

    @PersonalName(filedName = "你的名字")
    public String yourName="";

    @PersonalName(methodName = "打印A")
    public void printA(){
        System.out.println("A");
    }
}

public class JunitTest {

    private Class<?> test = TestBean.class;

    @Test
    public void testPrintFiled(){
        for(Field field:test.getDeclaredFields()){
            //getDeclaredAnnotations
            Annotation[] annotations = field.getDeclaredAnnotations();
            for (Annotation ann:annotations){
                if(ann instanceof PersonalName){
                    System.out.println("类:"+test.getName()+",属性:"+field.getName()+",自定义名:"+((PersonalName) ann).filedName());
                }
            }

            //getDeclaredAnnotation
            Annotation annotationFiled = field.getAnnotation(PersonalName.class);
            if(annotationFiled!=null){
                System.out.println("类:"+test.getName()+",属性:"+field.getName()+",自定义名:"+((PersonalName) annotationFiled).filedName());

            }
        }
    }

    @Test
    public void testMethod(){
        for(Method method:test.getDeclaredMethods()){
            Annotation annotationMethod = method.getAnnotation(PersonalName.class);
            if(annotationMethod!=null){
                System.out.println("类:"+test.getName()+",方法:"+method.getName()+",自定义名:"+((PersonalName) annotationMethod).methodName());
            }
        }
    }

    @Test
    public void testClass(){
        Annotation annotation = test.getAnnotation(PersonalName.class);
        TestBean testBean = null;
        if(annotation!=null){
            System.out.println("类:"+test.getName()+",自定义名:"+((PersonalName) annotation).className());
            try{
                testBean = (TestBean) test.newInstance();
                testBean.printA();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值