前几年我们的项目还在structs 2 上跑,有一次问一个同事是否知道Spring Boot,同事说那不是用注解来开发的吗。虽然这个答案并不完全对,但是从客观上Spring Boot对刚刚接触它的人来说最醒目的就是注解了。那么今天我们来了解一下Java语言的核心功能——注解。
注解是什么
public @interface
Anno {}
以上就是一个最简单的注解声明。它可以注释到类、接口、方法以及变量上。通过向方法,接口,类或字段添加注释,为其绑定的源代码分配额外的元数据。
注解的用途
通过注解我们可以通知编译器有关警告和错误的信息在编译时操作源代码在运行时修改或检查行为。jdk提供内置5个基本注解来处理代码检查。
注解可以将一些元数据传递给你编写的逻辑。比如Spring Mvc 中的一个常用注解@RequestMapping,我们可以通过value参数来传递一个path路径,Spring Mvc通过对请求的路径的匹配来作出是否路由到该path上。 目前大量的的框架都依赖注解,比如Spring、hibernate、dubbo等等。
元注解
元注解是可以应用于其他注解的注解。来增强或者配置目标注解的机制。jdk目前提供了5个元注解。如果你需要开发自定义注解,请务必熟悉它们:
RetentionPolicy.SOURCE 这种策略下被修饰的注解只能存在于源代码中,编译后被丢弃,通过反射无法获取到被修饰的注解。
RetentionPolicy.CLASS 这种策略下被修饰的注解会被编译进字节码文件中。但是JVM无法获取到被修饰的注解。这是一个默认值,当你声明的注解没有添加任何保留策略时,会默认指定该策略。
RetentionPolicy.RUNTIME 这种策略下被修饰的注解不但可以编译进字节码文件。而且JVM也可以获取被该注解修饰的注解。而且程序编码也可以通过反射来获取被该注解修饰的注解的一些元信息。
- TYPE 只能修饰 类、接口、枚举。
- FIELD 只能修饰成员变量,包含枚举内的常量。
- METHOD 只能修饰方法。
- PARAMETER 只能修饰参数。
- CONSTRUCTOR 只能修饰构造器。
- LOCAL_VARIABLE 只能修饰局部变量。
- ANNOTATION_TYPE 只能修饰注解。
- PACKAGE 只能修饰包定义。也就是package-info.java中
- TYPE_PARAMETER java 8 新增 表示该注解能写在类型参数的声明语句中。 类型参数声明如: <T>、<T extends Person>
- TYPE_USE java 8 新增 注解可以再任何用到类型的地方使用。
自定义注解
自定义注解跟自定义接口类似,但是还有一些区别,实际开发你需要对自定义注解进行元注解注释。注解中的成员变量以无参抽象方法来声明,成员变量并不是所有类型都支持,目前只支持以下类型:
下面我们就来自定义一个注解:
/** * 声明一个可以标记在类、接口、枚举、方法上的注解。 * 并且JVM Runtime 可见、可生成文档 * * @author Dax * @since 17 :27 2019/9/4 */@Documented@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.TYPE, ElementType.METHOD})public
@interface Anno {
/** * 若方法名为value且注解声明只需要声明value属性时, * value可以省略, @Anno("anno") 等同于 @Anno(value="anno") * * @return the string */ String value();
/** * 一个具有默认值的 String 类型属性。 * name若不显式声明,则默认值为"" 。 * 声明默认值通过 default + 默认值 来声明 * * @return the string */ String name() default
"";
/** * 一个Class 类型属性,没有默认值。其他支持类型不再举例 * * @return the class */ Class<?> clazz();}
获取注解中的元数据
所有的注解都是java.lang.annotation.Annotation 的子类。
只有RetentionPolicy为RUNTIME的 注解才能通过反射获取。在反射包中提供了AnnotatedElement 接口来对元素上的可捕捉到的注解进行处理。该接口是Class、Method、Constructor等程序元素对象的父接口。也就是说只要能获取程序元素对象就能对其存在的注解进行处理。主要方法有:
基本上对这个接口的方法进行学习后就可以知道如何获取注解的元数据了。下面我们写一个例子,还是上面的Anno注解为例:
/** * 被注解标记的类 **/@Anno("hello")public
class
Foo {}/** * 通过获取Foo 的Class 类, * 然后就可以根据上面已经介绍的方法来获取value的值了 * @author dax * @since 2019/9/4 22:17 */public
class
Main {
public
static
void
main(String[] args) { Anno annotation = Foo.class.getAnnotation(Anno.class); String value = annotation.value(); System.out.println("value = " + value); }}
总结
今天我们系统地对注解进行了归纳,相信你已经对注解有了系统性的认识。其实注解还可以干一些花式操作,比如lombok框架。后面我们会介绍相关的注解技术,多多关注。