[关闭]
@wuxin1994 2019-03-17T04:13:19.000000Z 字数 3921 阅读 90

Java注解

JAVA


概念

注解(Annotation)

也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
这些标记和注释可以在编译、类加载、运行时被读取,并执行响应的处理。
通俗地讲,注解相当于给类、属性或者方法贴上一个标签。

注解的元注解

元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。
元注解有五种:

  1. @Retention@Documented@Target@Inherited@Repeatable

注解的基本语法

定义

注解通过@interface 关键字定义。

  1. //创建一个名为AnnotationTest的注解。
  2. public @interface AnnotationTest{}

注解的属性

注解的属性类似于类的成员变量。并且注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
可以通过default关键字给出默认值。
举例:

  1. public @interface AnnotationTest{
  2. int id();
  3. String message() default "Hello World";
  4. }

在使用的时候,赋值的方式是在注解的括号内以 value=""形式,多个属性之间用","隔开。

  1. @AnnotationTest(id=0,message="God")
  2. public class Test{
  3. }
  4. //因为属性message有默认值,也可以不赋值
  5. @AnnotationTest(id=1)
  6. public class Test1{
  7. }
  8. //当所有属性都有默认值,括号内为空

甚至当注解没有属性时,可以不用括号:

  1. public @interface Check {
  2. }
  3. //没有属性的注解,不用括号
  4. @Check
  5. public class Test2{
  6. }

注意

注解中所有方法(也就是属性)没有方法体,且只允许public和abstract修饰。缺省默认为public,且注解方法不允许有throws子句。

注解中方法的返回值只能为:基本数据类型,String,Class,美剧类型,注解和他们的一维数组。

常见注解

五种元注解

前面我们提到,Java中有五种元注解。

  1. @Retention(RetentionPolicy.RUNTIME)
  2. public @interface AnnotationTest {
  3. }

能够将注解中的元素包含到 Javadoc 中去。

  1. @Inherited
  2. @Retention(RetentionPolicy.RUNTIME)
  3. @interface Test {}
  4. @Test
  5. public class A {}
  6. //因为Test注解被@Inherited注解,所以继承了注解了Test的A类后的B类,也拥有Test这个注解。
  7. public class B extends A {}

Repeatable 是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。

  1. @interface Persons {
  2. Person[] value();
  3. }
  4. @Repeatable(Persons.class)
  5. @interface Person{
  6. String role default "";
  7. }
  8. @Person(role="artist")
  9. @Person(role="coder")
  10. @Person(role="PM")
  11. public class SuperMan{
  12. }

@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。

什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。

我们再看看代码中的相关容器注解。

  1. @interface Persons {
  2. Person[] value();
  3. }

按照规定,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable 注解过的注解数组,注意它是数组。

可以这样理解。Persons 是一张总的标签,上面贴满了 Person 这种同类型但内容不一样的标签。把 Persons 给一个 SuperMan 贴上,相当于同时给他贴了程序员、产品经理、画家的标签。

Java预置注解

Java本身提供了现成的注解。

注解的作用

编译检查 编译器可以利用注解来探测错误和警告信息;通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

编写文档 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。通过代码里标识的元数据生成文档【生成文档doc文档】

代码分析 某些注解可以在程序运行的时候接受代码的提取;通过代码里标识的元数据对代码进行分析【使用反射】

总之,当开发者使用了Annotation 修饰了类、方法、Field 等成员之后,这些 Annotation 不会自己生效,必须由开发者提供相应的代码来提取并处理 Annotation 信息。这些处理提取和处理 Annotation 的代码统称为 APT(Annotation Processing Tool)。
而注解主要就是给编译器或者APT用的。

注解也就是代码添加元数据,描述信息。

相比使用单独的XML来描述这些元数据,使用注解要简单些,和代码在一起也更好维护。相比使用继承(如TesCase)或者方法前缀的约定(如testXXX是测试方法)要灵活些。

一些插件机制就是通过注解提供插件的元数据,在加载类后扫描所以带该注解的类就可以找到插件,减少了配置的麻烦。

反射和注解

注解的提取需要借助于 Java 的反射技术,反射比较慢,所以注解使用时也需要谨慎计较时间成本。

首先通过Class对象的isAnnotationPresent()方法判断他是否应用了某个注解:

  1. public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass){}

然后通过getAnnotation()方法获取Annotation对象。

  1. public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}

或者getAnnotations()方法:

  1. public Annotation[] getAnnotations() {}

如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法

  1. @AnnotationTest()
  2. public class Test {
  3. public static void main(String[] args) {
  4. boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
  5. if ( hasAnnotation ) {
  6. TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);
  7. System.out.println("id:"+testAnnotation.id());
  8. System.out.println("message:"+testAnnotation.message());
  9. }
  10. }
  11. }

参考1
参考2

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注