一、@Target的用法
java.lang.annotation.Target
用于设定注解使用范围
java.lang.annotation.ElementType
Target通过ElementType来指定注解可使用范围的枚举集合
二、ElementType的用法
取值 | 注解使用范围 |
METHOD | 可用于方法上 |
TYPE | 可用于类或者接口上 |
ANNOTATION_TYPE | 可用于注解类型上(被@interface修饰的类型) |
CONSTRUCTOR | 可用于构造方法上 |
FIELD | 可用于域上 |
LOCAL_VARIABLE | 可用于局部变量上 |
PACKAGE | 用于记录java文件的package信息 |
PARAMETER | 可用于参数上 |
这里重点说明下:ElementType. PACKAGE。它并不是使用在一般的类中,而是用在固定的文件package-info.java中。这里需要强调命名一定是“package-info”。由于package-info.java并不是一个合法的类,使用eclipse创建类的方式会提示不合法,所以需要以创建文件的方式来创建package-info.java。
例如,定义可使用范围PACKAGE:
那么,创建文件:package-info.java,内容如下:
复制代码 代码如下:
@AsynLog
package org.my.commons.logs.annotation;
重点说明:注解只能在ElementType设定的范围内使用,否则将会编译报错。例如:范围只包含ElementType.METHOD ,则表明该注解只能使用在类的方法上,超出使用范围将编译异常。
@Retention注解
日常开发中经常用到注解,所以也会经常使用到@Retention注解,写下这篇文章做个记。
Reteniton的作用是定义被它所注解的注解保留多久,一共有三种策略,定义在RetentionPolicy枚举中
public enum RetentionPolicy {
SOURCE,
CLASS,
RUNTIME
}
-
SOURCE
被编译器忽略 -
CLASS
注解将会被保留在Class文件中,但在运行时并不会被VM保留。这是默认行为,所有没有用Retention注解的注解,都会采用这种策略。 -
RUNTIME
保留至运行时。所以我们可以通过反射去获取注解信息。
下面,我们通过一个例子去验证一下。我定义了不同策略的注解去注解了三个方法
@Retention(RetentionPolicy.SOURCE)
public @interface SourceLevel {
}
@Retention(RetentionPolicy.CLASS)
public @interface ClassLevel {
}
@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimeLevel {
}
public class Test {
@SourceLevel
public void sourceLevel(){}
@ClassLevel
public void classLevel(){};
@RuntimeLevel
public void runtimeLevel(){};
}
通过javap获取到Test类的字节码
public void sourceLevel();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 5: 0
public void classLevel();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 7: 0
RuntimeInvisibleAnnotations:
0: #11()
public void runtimeLevel();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 9: 0
RuntimeVisibleAnnotations:
0: #14()
我们可以看到
1. 编译器并没有记录下sourceLevel方法的注解信息
2. 编译器分别使用了RuntimeInvisibleAnnotations和RuntimeVisibleAnnotations属性去记录了classLevel和runtimeLevel的注解信息
以上。
注解的使用非常简单,只需在需要注解的地方标明某个注解即可,例如在方法上注解:
|
例如在类上注解:
|
所以Java内置的注解直接使用即可,但很多时候我们需要自己定义一些注解,例如常见的spring就用了大量的注解来管理对象之间的依赖关系。下面看看如何定义一个自己的注解,下面实现这样一个注解:通过@Test向某类注入一个字符串,通过@TestMethod向某个方法注入一个字符串。
1.创建Test注解,声明作用于类并保留到运行时,默认值为default。
|
2.创建TestMethod注解,声明作用于方法并保留到运行时。
|
3.测试类,运行后输出default和tomcat-method两个字符串,因为@Test没有传入值,所以输出了默认值,而@TestMethod则输出了注入的字符串。
|