Java Annotation学习笔记

作为一个早期短暂从事过C++开发工作的程序员,我个人认为Annotation可能是Java与C++语言较大的不同点之一,这也是一个前C++程序员由衷认为Java可能、或许、maybe要比C++更好用的原因之一。二十多年来,Java一直保持着更新,不断完善并与时俱进,这可能是其多年来独领编程语言之风骚的重要原因。不多扯,入正题。(编程知识的学习,我一般会遵循这样的一个过程:先熟悉基本概念,再来个小程序跑起来看看,最后理论与程序相结合,加深认识并总结记录。)

1、什么是Annotation


Annotation被译作“注解”,标准的英译汉,但是这个译词并没有很好的反映Annotation在java中的意义,或许“标记”更好一些,也或许“标签”。

注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后的某个时刻非常方便地使用这些数据。——《Java编程思想》

注解是那些插入到源代码中使用其他工具可以对其进行处理的标签。——《Java核心技术卷2》

从《Java核心技术卷2》的定义来看,注解包含两点内容:其一,它是标签、标记;此外,这个标签(标记)可以使用其他工具进行处理。
那么,其他工具在哪里可以处理这些标签呢?一个是源码层,另一个是类文件。

注解不会改变程序的编译方式,对于包含注解和不包含注解的代码,Java编译器会生成相同的虚拟机指令。——《Java核心技术卷2》

综上,大致可以给出Java注解一个简单通俗的描述使用过程:定义标签,然后提供标签处理工具,最后是应用标签到其它的代码中。当然,Java自带的注解,我们就只需要直接使用就可以了,因为定义和处理工具Java都帮我们做好了。

2、来个sample


2.1定义标签

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
    
    public int id();
    
    public String description() default "No description";
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
Target和Retention是java语言自带的两个元注解,Target表示用户自定义的注解(UseCase)能应用在哪里(注解类型声明,包,类或接口、方法等);
Retention用来指明自定义注解应该保留多长的时间(取值为SOURCE/CLASS/RUNTIME)
public @interface UseCase
这是定义注解的语法形式,乍一看类似接口的定义,区别在于interface前加了一个@符号,后续使用该用户自定义注解时语法就是@UseCase
public int id();
public String description() default "No description";
这是注解中定义字段的语法,()并不表示这是一个方法,再者,注解中不支持定义方法。
同时,可以设置字段的默认值,通过default关键字。没有默认值的字段必须在使用时显示指明。

2.2 标签处理工具

import java.lang.reflect.*;

public class UseCaseTracker {

    public static void trackUseCase(Class<?> cl) {
        for (Method m : cl.getMethods()) {
            UseCase useCase = m.getAnnotation(UseCase.class);
            if (useCase != null) {
                System.out.println("Found Use Case : " + useCase.id() + " " + useCase.description());
            }
        }
    }

}
@Retention(RetentionPolicy.RUNTIME)中的RUNTIME使得注解可以保留到类文件中,并由虚拟机载入,这样我们就可以通过反射API来获得它们。接下来我就是通过反射API获得这些注解。
public static void trackUseCase(Class<?> cl) {
    for (Method m : cl.getMethods()) {
        UseCase useCase = m.getAnnotation(UseCase.class);
        if (useCase != null) {
            System.out.println("Found Use Case : " + useCase.id() + " " + useCase.description());
        }
    }
}
trackUseCase方法通过传入应用了UseCase注解的类,再通过反射API获得这些注解并打印注解中的信息。    

2.3 应用标签

import java.util.List;

public class PasswordUtils {
    
    @UseCase(id=47, description="Passwords must contain at least one numeric")
    public boolean validatePassword(String password) {
        return (password.matches("\\w*\\d\\w*"));
    }
    
    @UseCase(id=48)
    public String encryptPassword(String password) {
        return new StringBuilder(password).reverse().toString();
    }
    
    @UseCase(id=49, description="New passwords can't equal previously used ones")
    public boolean checkForNewPassword(List<String> prePasswords, String password) {
        return !prePasswords.contains(password);
    }
    
}
@Target(ElementType.METHOD)规定了注解只能是应用在方法上,因此,上述例子中便是如此。
@UseCase(id=47, description="Passwords must contain at least one numeric")
@UseCase(id=48)
@UseCase(id=49, description="New passwords can't equal previously used ones")
以上是三种使用应用自定义注解的例子。

2.4 测试

import java.lang.reflect.*;

public class UseCaseTracker {

    public static void trackUseCase(Class<?> cl) {
        for (Method m : cl.getMethods()) {
            UseCase useCase = m.getAnnotation(UseCase.class);
            if (useCase != null) {
                System.out.println("Found Use Case : " + useCase.id() + " " + useCase.description());
            }
        }
    }
    
    public static void main(String[] args) {
        trackUseCase(PasswordUtils.class);
    }

} 

直接在注解处理工具中加了个main方法来测试注解处理工具。输出结果如下:

Found Use Case : 47 Passwords must contain at least one numeric
Found Use Case : 49 New passwords can't equal previously used ones
Found Use Case : 48 No description

注:以上代码来自《Java编程思想》,部分有改动。

3、归纳整理


3.1 注解元素(属性)的类型

基本类型(int/short/long/byte/char/double/float/boolean)
String
Class
enum
注解类型
以上五种类型组成的数组

注:注解元素值不能为null,默认值也不能为null。

3.2 标准注解

Java Annotation学习笔记

3.3 Target注解的元素类型

元素类型定义在枚举类星Element中。
Java Annotation学习笔记

3.4 Retention注解的元素类型

Java Annotation学习笔记

上一篇:Java访问修饰符


下一篇:Perl语言面向对象入门