- java在JDK1.5以后引入了注解(Annotation)的功能。
- 注解主要用于说明代码的,是代码的特殊标记,因此是编译器和JVM可见的,而通常的注释是被编译器和JVM完全忽略的,这就是注解和注释的最主要区别。
- 注解主要有三个方面的作用:分别是编写文档、编译检查、代码分析
- JavaSE中,注解作用有限,但在JavaEE中,作用很大,可以代替XML配置
一、常用注解
1. 用于文档生成的注解
注解 | 作用 | 格式要求 | 备注 |
---|---|---|---|
@author | 标明开发该类的作者 | @author 姓名/组织/邮箱 | 多个作者之间用逗号隔开 |
@version | 标明该类的版本 | @version 当前版本号 | ———————— |
@see | 标明相关联的类 | @see 类名/方法名 | 可用于类和方法 |
@since | 从哪个版本开始增加 | @since 创建日期/初始版本号 | ———————— |
@param | 对方法参数的说明 | @param 形参名 形参类型 形参说明 | 1. 仅用于方法;2. 没有参数则不能写;3. 可并列多个 |
@return | 对方法返回值的说明 | @return 返回值类型 返回值说明 | 1. 仅用于方法;2.返回值是void则不能写 |
@exception | 对方法可能抛出的异常进行说明 | @exception 异常类型 异常说明 | 1. 仅用于方法;2.方法没有throws抛出则不能写;3. 可并列多个 |
2. 用于编译时格式检查的注解
注解 | 作用 | 格式要求 | 备注 |
---|---|---|---|
@Override | 限定重写父类方法 | @Override | 多个作者之间用逗号隔开 |
@Deprecated | 表示所修饰元素已过时,通常因为所修饰的结构或存在更好的选择 | @Deprecated | ———————— |
@SuppressWarnings | 抑制编译器警告 | @SuppressWarnings (“警告类型”) |
警告类型有deprecation、unchecked、fallthrough、path等 |
下面这段代码展示了以上注解的用法
1 | /** |
3. 用于替代配置文件的注解
Servlet3.0提供了注解,使得不需要在web.xml文件中进行Servlet的配置1
2
3
4
5
6
7
8<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>com.servlet.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login</url-pattern>
</servlet-mapping>
使用@WebServlet注解替代上述冗长的XML配置信息,如下所示。1
2
3
4
5
6
7
8
9
10
11
12
public class LoginServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
}
二、自定义注解
- 使用@interface声明自定义Annotation,本质上就是一个类
- 自定义注解自动继承java.lang.annotation.Annotation接口
- 自定义Annotation可以有成员变量,其类型可为八种基本数据类型、String类型、Class类型、enum类型、Annotation类型以及上述类型的数组形式
- 成员变量声明为无参数方法的形式,如String value();
- 没有成员变量的Annotation称为标记,包含成员变量的Annotation称为元数据Annotation
- 成员变量如果只有一个,一般命名为value,也可以用别的名字
- 成员变量如果有多个,可以用以value命名的数组,如String[] value();,也可用别的名字
- 使用 default 默认值 来为成员变量指定默认值,如String value() default “hello”;
- 如果没有给成员变量指定默认值,当在使用Annotation时,必须指定参数值,如@MyAnnotation(value = “hello”)
- 可以没有成员变量
下面是一个例子1
2
3
4
5
6
7
8public MyAnnotation {
String value() default "hello";
}
class Test{
}
三、元注解(meta-annotation)
- 元Annotation用于修饰其他Annotation
- JDK5.0提供了4个标准元注解,分别是@Retention、@Target、@Documented、@Inherited
注解 | 作用 | 格式要求 | 备注 |
---|---|---|---|
@Retention | 指定被修饰Annotation的生命周期 | @Retention(状态值) | 状态值有三种,见后文 |
@Target | 指定被修饰的Annotation能用于修饰哪些程序元素 | @Target({若干程序元素}) | 可指定元素见后文 |
@Documented | 指定被修饰的Annotation将被javadoc工具提取成文档 | @Documented | 定义为@Documented的注解必须设置Retention的值为RUNTIME |
@Inherited | 指定被修饰的Annotation具有继承性 | @Inherited | 所修饰的Annotation修饰的类的子类自动具有该注解 |
@Retention的成员变量可被指定为三种值:
- RetentionPolicy.SOURCE 意味所修饰的注解只在编译阶段起作用,不会保留在class文件中
- RetentionPolicy.CLASS 默认行为,所修饰注解会被保留在class文件中,但不会保留在运行阶段
- RetentionPolicy.RUNTIME 保留在class文件中,同时还保留在运行阶段,加载在内存当中,能通过反射获取
@Target的成员变量是一个数组,可被指定为一个或多个以下值:
- ElementType.TYPE
- ElementType.FIELD
- ElementType.METHOD
- ElementType.PARAMETER
- ElementType.CONSTRUCTOR
- ElementType.LOCAL_VARIABLE
关于@Documented,下面是一个例子1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19import java.lang.annotation.*;
public MyAnnotation {
String value() default "hello";
}
class Test{
}
//由于@Inherited的存在,kid类自动继承其父类Test的注解
class kid extends Test{
}
以下是JDK 8的新特性
四、可重复注解
在JDK 8以前,只能如此实现重复注解:1
2
3
4
5
6
7
8
9
10
11
12
13public MyAnnotations {
MyAnnotation[] value();
}
MyAnnotation {
String value() default "hello";
}
class Test{
}
jdk 8以来,可以这么实现1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
MyAnnotations{
MyAnnotation[] value();
}
MyAnnotation {
String value() default "hello";
}
class Test{
}
注:
1.在MyAnnotation上声明Repeatable,成员变量值为MyAnnotations.class
2.保证MyAnnotation的元注解@Retention和@Target和MyAnnotations的@Retention和@Target一模一样
五、类型注解
- JDK 8之后,@Target的参数类型ElementType枚举值多了两个:TYPE_PARAMETER和TYPE_USE
- JDK 8以前,注解只能写在声明的地方;JDK 8以后,注解可以写在任何地方,只要@Target值中包含TYPE_PARAMETER或TYPE_USE。
- ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中
- ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中
下面是ElementType.TYPE_PARAMETER的用法1
2
3
4
5
6
7
8
9
10import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
public class Generic< T> {
}
MyAnnotation{
String value() default "hello";
}
下面是ElementType.TYPE_USE的用法1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.util.ArrayList;
public class Generic< T> {
public void show() throws RuntimeException{
ArrayList<new ArrayList<>(); String> list =
int num = ( int) 10L;
}
}
MyAnnotation{
String value() default "hello";
}