Java 8 Annotation 新特性初体验

特性一:Type Annotation

在 Java 8 之前的版本中,只能允许在声明式前使用 Annotation。而在 Java 8 版本中,Annotation 可以被用在任何使用 Type 的地方,例如:初始化对象时 (new),对象类型转化时,使用 implements 表达式时,或者使用 throws 表达式时。

清单 1. Type Annotation 使用示例
//初始化对象时
String myString = new @NotNull String();
//对象类型转化时
myString = (@NonNull String) str;
//使用 implements 表达式时
class MyList<T> implements @ReadOnly List<@ReadOnly T>{
                    ...
 }
 //使用 throws 表达式时
 public void validateValues() throws @Critical ValidationFailedException{
                    ...
  }

定义一个 Type Annotation 的方法与普通的 Annotation 类似,只需要指定 Target 为 ElementType.TYPE_PARAMETER 或者 ElementType.TYPE_USE,或者同时指定这两个 Target。

清单 2. 定义 Type Annotation 示例
@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE})
public  @interface MyAnnotation {
}

ElementType.TYPE_PARAMETER 表示这个 Annotation 可以用在 Type 的声明式前,而 ElementType.TYPE_USE 表示这个 Annotation 可以用在所有使用 Type 的地方(如:泛型,类型转换等)

与 Java 8 之前的 Annotation 类似的是,Type Annotation 也可以通过设置 Retention 在编译后保留在 class 文件中(RetentionPolicy.CLASS)或者运行时可访问(RetentionPolicy.RUNTIME)。但是与之前不同的是,Type Annotation 有两个新的特性:在本地变量上的 Annotation 可以保留在 class 文件中,以及泛型类型可以被保留甚至在运行时被访问。

虽然 Type Annotation 可以保留在 class 文件中,但是它并不会改变程序代码本身的行为。例如在一个方法前加上 Annotation,调用此方法返回的结果和不加 Annotation 的时候一致。

Java 8 通过引入 Type Annotation,使得开发者可以在更多的地方使用 Annotation,从而能够更全面地对代码进行分析以及进行更强的类型检查。

特性二:Repeating Annotation

在实际应用中,可能会出现需要对同一个声明式或者类型加上相同的 Annotation(包含不同的属性值)的情况。

例如系统中除了管理员之外,还添加了超级管理员这一权限,对于某些只能由这两种角色调用的特定方法,可以使用 Repeating Annotation。

清单 3. Repeating Annotation 使用示例-1
@Access(role="SuperAdministrator")
 @Access(role="Administrator")
 public void doCheck() { 
              ......
 }

上面的示例是针对方法使用 Annotation, 开发者也可以根据产品中的具体需求在其他地方使用 Repeating Annotation。例如某个类专门提供管理员相关的功能,可以直接在这个类上标注同样的 Annotation。

清单 4. Repeating Annotation 使用示例-2
@Access(role="SuperAdministrator")
@Access(role="Administrator")
public class AdminServices{
}

之前版本的 JDK 并不允许开发者在同一个声明式前加注同样的 Annotation,(即使属性值不同)这样的代码在编译过程中会提示错误。而 Java 8 解除了这一限制,开发者可以根据各自系统中的实际需求在所有可以使用 Annotation 的地方使用 Repeating Annotation。

由于兼容性的缘故,Repeating Annotation 并不是所有新定义的 Annotation 的默认特性,需要开发者根据自己的需求决定新定义的 Annotation 是否可以重复标注。Java 编译器会自动把 Repeating Annotation 储存到指定的 Container Annotation 中。而为了触发编译器进行这一操作,开发者需要进行以下的定义:

首先,在需要重复标注特性的 Annotation 前加上 @Repeatable 标签,示例如下:

清单 5. 定义 Repeating Annotation 示例
@Repeatable(AccessContainer.class)
public @interface Access {
        String role();
}

@Repeatable 标签后括号中的值即为指定的 Container Annotation 的类型。在这个例子中,Container Annotation 的类型是 AccessContainer,Java 编译器会把重复的 Access 对象保存在 AccessContainer 中。

AccessContainer 中必须定义返回数组类型的 value 方法。数组中元素的类型必须为对应的 Repeating Annotation 类型。具体示例如下:

清单 6. 定义 Container Annotation 示例
public @interface AccessContainer {
       Access[] value();
}

可以通过 Java 的反射机制获取注解的 Annotation。一种方式是通过 AnnotatedElement 接口的 getAnnotationByType(Class<T>) 首先获得 Container Annotation,然后再通过 Container Annotation 的 value 方法获得 Repeating Annotation。另一种方式是用过 AnnotatedElement 接口的 getAnnotations(Class<T>) 方法一次性返回 Repeating Annotation。

Repeating Annotation 使得开发者可以根据具体的需求对同一个声明式或者类型加上同一类型的注解,从而增加代码的灵活性和可读性。

results matching ""

    No results matching ""