注解

转载自大神谷歌小弟的博客

An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.

Annotation作为元数据可以被添加到Java源代码 类、方法、变量、参数、包。虽然源码中添加了注释,但是Annotation**不会直接影响程序的执行**,无论增加或者删除Annotation,原代码的执行都始终如一。在中文里,常将Annotation翻译为“注解”,在以下的论述中也采用该译法

1. 标准注解

在Java的JDK中内置了一些系统自带的注解,这些注解也常称为标准注解,常见的有:

  • @Override
  • @Deprecated
  • @SuppressWarnings

1.1 @Override

@Override作用于方法,表示被标注的方法重载了父类的方法。若该重载的方法写错了方法名那么在编译期就会有出现警告

这里写图片描述

看到了吧,在子类Customer中用@Override标记了方法setId()表示这个方法是重载自父类;假若把方法名错写成了setIdd()编译器就会报错了。

1.2 @Deprecated

当一个类型或者类型成员使用@Deprecated标记则表示建议不再使用该元素

这里写图片描述
这里写图片描述

在User类中,将setId()方法标记为@Deprecated,当我们准备调用该方法时编译器就会提示该方法已经过时,建议换用其他方法

1.3 @SuppressWarnings

@SuppressWarnings翻译成中文就是抑制警告,它被用于关闭编译器对类、方法、成员变量、变量初始化的警告

这里写图片描述

定义了一个变量testSuppressWarnings,但是该变量从未被使用,所以提示了一个警告:private field ‘testSuppressWarnings’ is never used。为了抑制该警告,我们给testSuppressWarnings添加一个注解:

@SuppressWarnings(“unused”)

这里写图片描述

该注解就表示不再警告变量未被使用。
除了该处使用的unused以外@SuppressWarnings还有许多其他参数,比如:

  • serial:可序列化的类上缺少serialVersionUID定义的警告
  • finally:finally语句不能正常完成的警告
  • deprecation:使用了过时的类型或者类型成员方法时的警告
  • unchecked:执行了未检查的转换的警告
  • all:所有情况的警告

2. 自定义注解

除了使用系统提供的注解,我们当然也可以自定义注解。

自定义注解和创建接口非常相似,但注解需要以@开头方法体中的每一个方法实际上是声明了一个属性,其中方法名是属性的名称,方法的返回值类型就是属性的类型(返回值类型只能是基本类型、String、enum、Class)。当然也可以通过default来声明属性的默认值。
比如:

public @interface TestAnnotation {
    public String name();
    public int age() default 20;
}

如上代码就定义了一个自定义的注解TestAnnotation,它有两个属性name和age,并且age的默认值为20
有时注解中只需要一个属性,为简便起见可将该属性命名为value,比如:

@Retention(RetentionPolicy.RUNTIME)
public @interface ValueAnnotation {
   String value();
}

如上代码就定义了一个自定义的注解ValueAnnotation,并且该注解只有一个属性value。其实,@SuppressWarnings也与此类似。
在定义完成之后,现再将这个两个自定义的注解作用于类

@TestAnnotation(name="lucy")
@ValueAnnotation("lucy9527")
public class Beauty {

}

在这段代码中为类Beauty添加了两个注解。在使用注解TestAnnotation时采用键值对的形式为属性name赋值,在使用注解ValueAnnotation时由于其只有一个属性value,所以可将value = “lucy9527”简写成”lucy9527”。

好了,在一个类上使用了自定义注解,现再瞅瞅怎么样把这些注解的属性值提取出来

/**
 * 提取自定义注解的属性
 */
private void getAnnotationValue(){
    TestAnnotation annotation = null;
    Class clazz=Beauty.class;
    boolean isPresent= clazz.isAnnotationPresent(TestAnnotation.class);
    if(isPresent){
        annotation = (TestAnnotation)clazz.getAnnotation(TestAnnotation.class);
        String name=annotation.name();
        int age=annotation.age();
        System.out.println("----> annotation=" + annotation);
        System.out.println("----> name=" + name+",age="+age);
    }
 }

/**
 * 提取自定义注解的属性
 */
private void getAnnotationDefaultValue(){
    ValueAnnotation annotation = null;
    Class clazz=Beauty.class;
    boolean isPresent= clazz.isAnnotationPresent(TestAnnotation.class);
    isPresent= clazz.isAnnotationPresent(ValueAnnotation.class);
    if(isPresent){
        annotation= (ValueAnnotation) clazz.getAnnotation(ValueAnnotation.class);
        String value=annotation.value();
        System.out.println("----> defaultValue=" + value);
    }
}

2.1 主要步骤如下

第一步,先判断该注解是否存在,即:

clazz.isAnnotationPresent(TestAnnotation.class);

第二步,获取注解,即:

annotation =(TestAnnotation)clazz.getAnnotation(TestAnnotation.class);

第三步,获取注解的属性值,即:

String name=annotation.name(); 
int age=annotation.age();

输出结果:

-> annotation=@cc.testreflection.TestAnnotation(age=20, name=lucy) 
—-> name=lucy,age=20-> defaultValue=lucy9527

3. 元注解

刚才通过三个系统的标准注解和自定义注解我们看到:注解是用来标记或者说明类,方法,变量的

与此类似,Java还提供了元注解用于标记注解
常见的元注解有:

  • @Target
  • @Retention
  • @Documented
  • @Inherited

3.1 @Target

@Target用于确定Annotation所修饰的对象范围。我们知道Annotation可用于packages、types(类、接口、枚举)、类型成员(方法、成员变量、枚举值)、方法参数等等。所以,可用@Target表示Annotation修饰的目标。

比如@Override的源码:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {

}

在此使用了元注解@Target表示@Override只能用于修饰方法。

除ElementType.METHOD以外,@Target还可以使用其他的值用于表示注解的修饰对象,比如:

  • CONSTRUCTOR:用于描述构造器
  • FIELD:用于描述类成员变量
  • LOCAL_VARIABLE:用于描述局部变量
  • PACKAGE:用于描述包
  • PARAMETER:用于描述参数

3.2 @Retention

@Retention**定义了Annotation的有效范围,类似于Android中常提到的生命周期。**Java文件从生产到执行,要经过三个主要的阶段:java源文件,Class文件,JVM运行。与此类似,有的Annotation仅出现在源代码中而被编译器丢弃,而另一些却被编译在Class文件中;有的编译在Class文件中的Annotation在运行时会被虚拟机忽略,而另一些在运行时被读取读取

所以,在@Retention中使用RetentionPoicy标明注解会存留到哪个阶段,RetentionPoicy有三个值:

  • SOURCE:在源文件中有效(即仅在源文件保留)
  • CLASS:在Class文件中有效(即Class保留)
  • RUNTIME:在运行时有效(即保留至运行时)

比如@Deprecated的源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {

}

在这段源码中用@Retention(RetentionPolicy.RUNTIME)标明该注解会保留至运行时

3.3 @Documented

@Documented表示在生成javadoc文档时将该Annotation也写入到帮助文档

比如有一个注解:

@Target(ElementType.METHOD)
@Documented  
public @interface TestDocumented {   
     String name();   
} 

在此使用@Target(ElementType.METHOD)表示这个注解是用来修饰方法的,并且为该注解添加了元注解@Documented

public class CommonClass {   
    /**  
     * This is a java method  
     */  
    @TestDocumented(name = "google")   
    public void testMethod() {   

     }  

} 

然后在一个方法上使用注解@DocumentTest

@TestDocumented(name = “google”) 
public void testMethod() 
This is a java method

最后生成类似如上所示的帮助文档

3.4 @Inherited

@Inherited用于指示注释类型被自动继承
参见如下完整示例

第一步: 定义一个注解,并在该注解上使用了元注解@Inherited

@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InheritedAnnotation {
    String value( );
}

第二步:
定义一个父类,并且在该类上使用了自定义注解@InheritedAnnotation

@InheritedAnnotation("@InheritedAnnotation on class of ParentClass")
public class ParentClass {
    public void print() {
            System.out.println("----> This is parent print( )");
    }
}

第三步: 定义一个子类继承自父类。

public class ChildClass extends ParentClass {

}

第四步: 测试子类是否继承父类中类上的注解

public  void testInheritedOnClass(){
    InheritedAnnotation annotation=null;
    Class clazz = ChildClass.class;
    Class annotationClass=InheritedAnnotation.class;
    boolean isPresent=clazz.isAnnotationPresent(annotationClass);
    if (isPresent) {
        annotation = (InheritedAnnotation) clazz.getAnnotation(annotationClass);
        String value = annotation.value();
        System.out.println("----> value=" + value);
    }
}

输出结果为:

-> value=@InheritedAnnotation on class of ParentClass
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值