从J2SE 5.0时代开始,注解一直是Java的重要组成部分。 在我们的应用程序代码中的某些地方,我们经常看到过类似@Override 和的注释 @Deprecated。注解有什么含义,为什么引入的注解,它们是如何工作的工作方式,如何编写自定义注释,这些就是我们今天要讨论的。
什么是注解?
用一个词来解释注解就是元数据。元数据就是关于数据的数据。因此,注解就是代码的元数据。即使我们不写注解,我们的程序代码也可以正常工作。那么我们写注解的目的是什么?
比如@Override注解是告诉编译器此方法是重写的方法,如果父类中不存在任何这样的方法,则编译器会抛出异常。现在,如果我犯了一个书写错误,我重写的方法名写错了,如果我没有加上注解,那么我的代码将成功编译并执行,但是却不是我想要的结果。如果我加上了注解,那么编译器就会提示我父类不存在复写的方法。
注解的实现原理
从java源码到class字节码是由编译器完成的,编译器会对java源码进行解析并生成class文件,而注解也是在编译时由编译器进行处理,编译器会对注解符号处理并附加到class结构中,根据jvm规范,class文件结构是严格有序的格式,唯一可以附加信息到class结构中的方式就是保存到class结构的attributes属性中。我们知道对于类、字段、方法,在class结构中都有自己特定的表结构,而且各自都有自己的属性,而对于注解,作用的范围也可以不同,可以作用在类上,也可以作用在字段或方法上,这时编译器会对应将注解信息存放到类、字段、方法自己的属性上。
注解的本质就是一个继承Annotation接口的接口,当我们通过AnnotationTest.class.getAnnotation(Test.class)调用时,JDK会通过动态代理生成一个实现了Test接口的对象,并把将RuntimeVisibleAnnotations属性值设置进此对象中,此对象即为Test注解对象,通过它的value()方法就可以获取到注解值。
Java注解实现机制的整个过程如上面所示,它的实现需要编译器和JVM一起配合。
如何写注解
编写注解非常简单。您可以将注解定义与接口定义进行比较。
@Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
这就是一个注解的定义,定义好之后,我们只要在代码前使用@Override就可以使用注解了。
当我们谈论诸如的标准注解的时候, JVM是使用者,它在字节码级别工作。现在,这是应用程序开发人员无法控制并且不能用于自定义注释的功能。因此,我们需要自己给消费者写注释。
J2SE 5.0在java.lang.annotation包中提供了四个注解,这些注解仅在编写注解时候使用:
@Documented –是否在Javadocs中添加注释
@Retention –需要注释时,定义注释应保留多长时间
@Target? –放置注释的位置
@Inherited –子类是否获得注释。
自定义注解
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface Todo { public enum Priority {LOW, MEDIUM, HIGH} public enum Status {STARTED, NOT_STARTED} String author() default "Yash"; Priority priority() default Priority.LOW; Status status() default Status.NOT_STARTED; }
以下是如何使用上述的注解:
@Todo(priority = Todo.Priority.MEDIUM, author = "Yashwant", status = Todo.Status.STARTED) public void incompleteMethod1() { //一些没有完成的方法 }
注解案例
注解功能非常强大,Spring和Hibernate之类的框架将注解广泛用于日志记录和验证。注解可以在使用标记接口的地方使用。标记接口用于完整的类,但是您也可以定义在单个方法上使用的注解,例如,某个方法是否作为服务方法公开。
在Servlet规范3.0中,引入了许多注解,尤其是与Servlet安全性相关的注解。让我们看看一些:
MultipartConfig –此注释用于指示声明了它的Servlet希望使用multipart / form-data MIME类型进行请求。
ServletSecurity –在Servlet实现类上声明此注释,以对HTTP协议请求强制实施安全性约束。
WebFilter –用于声明Servlet过滤器的注释。
WebInitParam –用于在WebFilter 或 WebServlet 注释内的Servlet或过滤器上声明初始化参数的 注释。
WebListener — 在给定的Web应用程序上下文中用于声明各种事件的侦听器的注释。
WebServlet –此注释用于声明Servlet的配置。