Java Annotation学习笔记

    xiaoxiao2023-06-16  163

    作为一个早期短暂从事过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 标准注解

    3.3 Target注解的元素类型

    元素类型定义在枚举类星Element中。

    3.4 Retention注解的元素类型

    相关资源:敏捷开发V1.0.pptx
    最新回复(0)