注解你真的深入了解了吗?(3)

介绍了什么是元数据,元数据的重要性,以及如何使用 J2SE 5.0(也叫做 Tiger)的基本内置注释。如果习惯了这些概念,您可能已经在想,Java 5 提供的三种标准注释也并不是特别健壮,能使用的只有 Deprecated SuppressWarnings Override 而已。所幸的是,Tiger 还允许定义自己的注释类型。在本文中,我将通过一些示例引导您掌握这个相对简单的过程。您还将了解如何对自己的注释进行注解,以及这样做的一些好处。我要感谢 O'Reilly Media, Inc.,他们非常慷慨地允许我在本文中使用我关于 Tiger 的书籍的注释一章中的代码示例。

  定义自己的注释类型


通过添加了一个小小的语法(Tiger 添加了大量的语法结构),Java 语言支持一种新的类型 —— 注释类型(annotation type)。注释类型看起来很像普通的类,但是有一些特有的性质。最明显的一点是,可以在类中以符号( @ )的形式注释其他 Java 代码。我将一步一步地介绍这个过程。

  @interface 声明


定义新的注释类型与创建接口有很多类似之处,只不过 interface 关键字之前要有一个 @ 符号。清单 1 中给出的是一个最简单的注释类型的示例:
清单 1. 非常简单的注释类型

package com.easyway.commons.ispace.dev.advances.datameta.custom;

/**

 *

 * @author longgangbai

 * @date 2010-5-21

 * @version 1.0

 * @since JDK6.0

 */

public @interface InProgress {}

  清单 1 的含义非常明显。如果编译这个注释类型,并确信其位于类路径中,那么您就可以在自己的源代码方法中使用它,以指出某个方法或类仍在处理中,如清单 2 所示:

清单 2. 使用定制的注释类型

package com.easyway.commons.ispace.dev.advances.datameta.custom;

 

import com.easyway.commons.ispace.dev.advances.datameta.custom.TODO.TODOType;

/**

 * 自定义注解

 * @author longgangbai

 * @date 2010-5-21

 * @version 1.0

 * @since JDK6.0

 */

@InProgress

@TODOItems({// Curly braces indicate an array of values is being supplied

      @TODO(

       severity=TODOType.CRITICAL,

       item="Add functionality to calculate the mean of the student's grades",

       assignedTo="Brett McLaughlin"

       ),

       @TODO(

       severity=TODOType.IMPOTANT,

       item="Print usage message to screen if no command-line flags specified",

       assignedTo="Brett McLaughlin"

       ),

       @TODO(

       severity=TODOType.LOW,

       item="Roll a new website page with this class's new features",

       assignedTo="Jason Hunter"

       )

})

public class CustomerMeta {}

  清单 1 所示注释类型的使用方法和内置注释类型的使用方法完全相同,只不过要同时使用名称和所在的包来指示定制注释。当然,一般的 Java 规则仍然适用,您可以导入该注释类型,直接使用 @InProgress 引用它。

  添加成员


上面所示的基本用法还远远不够健壮。您一定还记得 1 部分中曾经提到的,注释类型可以有成员变量。这一点非常有用,尤其是准备将注释作为更加复杂的元数据,而不仅仅将它作为原始文档使用的时候。代码分析工具喜欢加工大量的信息,定制注释可以提供这类信息。

  注释类型中的数据成员被设置成使用有限的信息进行工作。定义数据成员后不需要分别定义访问和修改的方法。相反,只需要定义一个方法,以成员的名称命名它。数据类型应该是该方法返回值的类型。清单 3 是一个具体的示例,它澄清了一些比较含糊的要求:

  清单 3. 向注释类型添加成员
package com.easyway.commons.ispace.dev.advances.datameta.custom;

 

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

 

/**

 * 自定义注解

 * @author longgangbai

 * @date 2010-5-21

 * @version 1.0

 * @since JDK6.0

 */

@Target(ElementType.METHOD) //仅仅使用于方法

@Retention(RetentionPolicy.RUNTIME) //注解咋运行时,编译执行

public @interface TODO{

    TODOType severity() default TODOType.LOW;

    String item();

    String assignedTo();

    enum TODOType{

       CRITICAL,IMPOTANT,LOW

    }

}

尽管清单 3 看起来很奇怪,但这是注释类型所要求的格式。清单 3 定义了一个名为 value 的字符串,该注释类型能够接受它。
   
当然作为编码人员,我们都不愿意跟这种加长版搅在一起。不过要注意,只有当注释类型只有 一个 成员变量,而且变量名为 value 时,才能使用简写形式。如果不符合这个条件,那么就无法利用这种特性。


设置默认值
    
迄今为止,您已经有了一个很好的起点,但是要做得完美,还有很长的一段路要走。您可能已经想到,下一步就要为注释设置某个默认值。如果您希望用户指定某些值,但是只有这些值与默认值不同的时候才需要指定其他的值,那么设置默认值就是一种很好的办法。来自 清单 4 TODO 注释类型的一个全功能版本,示范了这个概念及其实现:
   @TODO
注释类型中添加了几个新的变量。因为该注释类型的成员变量不是一个,所以将一个变量命名为 value 没有任何意义。只要成员变量多于一个,就应该尽可能准确地为其命名。

  另一个新特性是注释类型定义了自己的枚举(枚举,即 enumeration,通常也称为 enums,是 Java 5 的另一个新特性。它并没有多么地不同凡响,对注释类型更是如此)。然后,清单 6 使用新定义的枚举作为一个成员变量的类型。

  最后,再回到我们的主题 —— 默认值。建立默认值的过程非常琐碎,需要在成员声明的后面添加关键字 default ,然后提供默认值。正如您所料,默认值的类型必须与成员变量声明的类型完全相同。同样,这也不是什么火箭科学,只不过是词法上的变异。清单 7 给出了一个具体应用中的 GroupTODO 注释,其中 没有 指定 severity 成员:

对注释的注释
结束关于注释的讨论之前(至少在本系列文章中),我想简要地讨论一下注释的注释。

1 部分中所接触的预定义注释类型都有预定义的目的。但是在编写自己的注释类型时,

注释类型的目的并不总是显而易见的。除了基本的文档外,可能还要针对某个特定的成员类

型或者一组成员类型编写类型。这就要求您为注释类型提供某种元数据,以便编译器保证按

照预期的目的使用注释。

  当然,首先想到的就是 Java 语言选择的元数据形式 —— 注释。您可以使用 4 种预定义的注释类型(称为 元注释)对您的注释进行注释。我将对这 4 种类型分别进行介绍。

 

你可能感兴趣的:(数据结构,J2SE)