JAVA基础-注解

105 阅读5分钟

注解基础

注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包、类、接口、字段、方法参数、局部变量等进行注解。它主要的作用有以下四方面:

  • 生成文档,通过代码里标识的元数据生成javadoc文档。
  • 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。
  • 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
  • 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。

注意:注解是不支持继承

JAVA自带注解

包括@Override@Deprecated@SuppressWarnings

  • @Override:表示当前的方法定义将覆盖父类中的方法
  • @Deprecated:表示代码被弃用,如果使用了被@Deprecated注解的代码则编译器将发出警告
  • @SuppressWarnings:表示关闭编译器警告信息

元注解

在JDK 1.5中提供了4个标准的元注解:@Target@Retention@Documented@Inherited, 在JDK 1.8中提供了两个元注解 @Repeatable@Native

Target

Target注解用来说明那些被它所注解的注解类可修饰的对象范围:注解可以用于修饰 packages、types(类、接口、枚举、注解类)、类成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数),在定义注解类时使用了@Target 能够更加清晰的知道它能够被用来修饰哪些对象,它的取值范围定义在ElementType 枚举中。

public enum ElementType {
    TYPE,// 类、接口、枚举类
    FIELD,// 成员变量(包括:枚举常量)
    METHOD,// 成员方法
    PARAMETER,// 方法参数
    CONSTRUCTOR,// 构造方法
    LOCAL_VARIABLE,// 局部变量
    ANNOTATION_TYPE,// 注解类
    PACKAGE,// 可用于修饰:包
    TYPE_PARAMETER,// 类型参数,JDK 1.8 新增
    TYPE_USE;// 使用类型的任何地方,JDK 1.8 新增

    private ElementType() {
    }
}

Reteniton

Reteniton注解用来限定那些被它所注解的注解类在注解到其他类上以后,可被保留到何时,一共有三种策略,定义在RetentionPolicy枚举中。

public enum RetentionPolicy {
    SOURCE,    // 源文件保留
    CLASS,       // 编译期保留,默认值
    RUNTIME   // 运行期保留,可通过反射去获取注解信息
}

Documented

Documented注解的作用是:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息。

Inherited

Inherited注解的作用:被它修饰的Annotation将具有继承性。如果某个类使用了被@Inherited修饰的Annotation,则其子类将自动具有该注解。

Repeatable

重复注解:在java1.8添加,允许在同一申明类型(类,属性,或方法)的多次使用同一个注解。 java 8之前也有重复使用注解的解决方案,但可读性不是很好。事例代码:

//JAVA 1.5实现重复注解
public @interface Authority {
     String role();
}

public @interface Authorities {
    Authority[] value();
}

public class Test {

    @Authorities({@Authority(role="Admin"),@Authority(role="Manager")})
    public void doSome(){
    }
}

//JAVA 8 实现重复注解
@Repeatable(Authorities.class)
public @interface Authority {
     String role();
}

public @interface Authorities {
    Authority[] value();
}

public class Test {
    @Authority(role="Admin")
    @Authority(role="Manager")
    public void doSome(){ }
}

Native

使用 @Native 注解修饰成员变量,则表示这个变量可以被本地代码引用,常常被代码生成工具使用。对于 @Native 注解不常使用,了解即可

注解与反射接口

在自定义注解中,@Reteniton 使用RUNTIME类型。可以通过反射包java.lang.reflect下的AnnotatedElement接口提供这些方法。获取注解内容。

AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的方法来访问Annotation信息。

  • boolean isAnnotationPresent(Class<?extends Annotation> annotationClass)

判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false。注意:此方法会忽略注解对应的注解容器。

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass)

返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。

  • Annotation[] getAnnotations()

返回该程序元素上存在的所有注解,若没有注解,返回长度为0的数组。

  • <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)

返回该程序元素上存在的、指定类型的注解数组。没有注解对应类型的注解时,返回长度为0的数组。该方法的调用者可以随意修改返回的数组,而不会对其他调用者返回的数组产生任何影响。getAnnotationsByType方法与 getAnnotation的区别在于,getAnnotationsByType会检测注解对应的重复注解容器。若程序元素为类,当前类上找不到注解,且该注解为可继承的,则会去父类上检测对应的注解。

  • <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)

返回直接存在于此元素上的所有注解。与此接口中的其他方法不同,该方法将忽略继承的注释。如果没有注释直接存在于此元素上,则返回null

  • <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)

返回直接存在于此元素上的所有注解。与此接口中的其他方法不同,该方法将忽略继承的注释

  • Annotation[] getDeclaredAnnotations()

返回直接存在于此元素上的所有注解及注解对应的重复注解容器。与此接口中的其他方法不同,该方法将忽略继承的注解。如果没有注释直接存在于此元素上,则返回长度为零的一个数组。该方法的调用者可以随意修改返回的数组,而不会对其他调用者返回的数组产生任何影响。

自定义注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface TestMethodAnnotation {

    public String name() default "";

    public String value() default "";

}

public class Test{
    @TestMethodAnnotation(name="11",value="22")
    public void test1(){

    }
}

public class Main{
    public static void main(String[] args){
    Method[] methods= Test.class.getMethods()
    for (Method method : methods) {
            // 方法上是否有TestMethodAnnotation注解
            if (method.isAnnotationPresent(TestMethodAnnotation.class)) {
                try {
                    // 获取并遍历方法上的所有注解
                    for (Annotation anno : method.getDeclaredAnnotations()) {
                        System.out.println("Annotation in Method '"
                                + method + "' : " + anno);
                    }
                    // 获取MyMethodAnnotation对象信息
                    TestMethodAnnotation methodAnno = method
                            .getAnnotation(TestMethodAnnotation.class);

                    System.out.println(methodAnno.name());

                } catch (Throwable ex) {
                    ex.printStackTrace();
                }
            }
        }
    }

}