- 注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据
- 注解可以提供用来完整地描述程序所需的信息,而这些信息是无法用Java来表达的。因此,注解使得我们能够以将由编译器来测试和验证的格式,存储有关程序的额外信息
- 几个注解:
- @Override:表示当前的方法定义将覆盖超类中的方法
- @Deprecated:如果程序员使用了注解为它的元素,那么编译器会发出警告信息
- @SuppressWarnings:关闭不当的编译器警告信息
- 注解是正真的语言机的概念,一旦构造出来,就像有编译期的类型检查保护。注解是在实际的源代码级别保存所有的信息,而不是某种注释性文字,使得代码更整洁,且便于维护
- 定义注解实例:
-
1234567891011
package
annotationTest;
import
java.lang.annotation.ElementType;
import
java.lang.annotation.Retention;
import
java.lang.annotation.RetentionPolicy;
import
java.lang.annotation.Target;
@Target
(ElementType.METHOD)
@Retention
(RetentionPolicy.RUNTIME)
public
@interface
Test{}
- 在定义注解时,会需要一些元注解,如@Target和@Retention:
- @Targer:用来定义你的注解将应用于什么地方,一个方法或者一个域
- @Retention:用来定义该注解是哪一级别可用,在源代码中(SOURCE)、类文件中(CLASS)或者运行时(RUNTIME)
- 在注解中一般都会包含一些元素以表示某些值,当分析处理注解时,程序或工具可以利用这些值。注解的元素看起来就像接口的方法,唯一区别是你可以为其指定默认值。没有元素的注解称为标记注解,例如@Test
- 包含值的注解UserCase:
-
1234567891011121314
package
annotationTest;
import
java.lang.annotation.ElementType;
import
java.lang.annotation.Retention;
import
java.lang.annotation.RetentionPolicy;
import
java.lang.annotation.Target;
@Target
(ElementType.METHOD)
@Retention
(RetentionPolicy.RUNTIME)
public
@interface
UserCase {
public
int
id();
public
String description()
default
"no description"
;
}
- 如上可以看到description元素有一个default值,如果在注解某个方法时没有各处description的值,则该注解的处理器就会使用此元素的默认值”no description“
-
- 包含值的注解UserCase的实例:
-
12345678910111213141516171819202122
package
annotationTest;
import
java.util.List;
public
class
PasswordUtils {
@UserCase
(id =
47
, description =
"Passwords must contatin at least one numeric"
)
public
boolean
validatePassword(String password) {
return
(password.matches(
"\\w*\\d\\w*"
));
}
@UserCase
(id =
48
)
public
String encryptPassword(String password) {
return
new
StringBuilder(password).reverse().toString();
}
@UserCase
(id =
49
, description =
"New passwords can't equal previously used ones"
)
public
boolean
checkForNewPassword(List<String> prevPasswords,
String password) {
return
!prevPasswords.contains(password);
}
}
- 注解的元素在使用时表现为名-值对的形式
-
- 包含值的注解UserCase:
-
- 元注解:
- Java目前只内置了三种标准注解,以及四种元注解。元注解专职负责注解其他的注解:
- @Target:表示该注解可以用于什么地方,其ElementType参数包括:
- CONSTRUCTOR:构造器的声明
- FIELD:域声明(包括enum实例)
- LOCAL_VARIABLE:局部变量声明
- METHOD:方法声明
- PACKAGE:包声明
- PARAMETER:参数声明
- TYPE:类、接口(包括注解类型)或enum声明
- @Retention:表示需要在什么级别保存该注解信息,可选的RetentionPolicy参数有:
- SOURCE:注解将被编译器丢弃
- CLASS:注解在class文件中可用,但会被VM丢弃
- RUNTIME:VM将在运行期也保留注解,因此可以通过反射机制读取注解的信息
- @Documented:将此注解包含在Javadoc中
- @Inherited:允许子类继承父类中的注解
- @Target:表示该注解可以用于什么地方,其ElementType参数包括:
- Java目前只内置了三种标准注解,以及四种元注解。元注解专职负责注解其他的注解:
- 编写注解处理器:
- 如果没有用来读取注解的工具,那注解不会比注释更有用。使用注解的过程中,很重要的一个部分就是创建与使用注解处理器
-
1234567891011121314151617181920212223242526272829
package
annotationTest;
import
java.lang.reflect.Method;
import
java.util.ArrayList;
import
java.util.Collections;
import
java.util.List;
public
class
UserCaseTracker {
public
static
void
trackUserCases(List<Integer> useCases, Class<?> cl) {
for
(Method m : cl.getDeclaredMethods()) {
UserCase uc = m.getAnnotation(UserCase.
class
);
if
(uc !=
null
) {
System.out.println(
"Found Use Case:"
+ uc.id() +
" "
+ uc.description());
useCases.remove(
new
Integer(uc.id()));
}
}
for
(
int
i : useCases) {
System.out.println(
"Warning: Missing use case-"
+ i);
}
}
public
static
void
main(String[] args) {
List<Integer> useCases =
new
ArrayList<Integer>();
Collections.addAll(useCases,
47
,
48
,
49
,
50
);
trackUserCases(useCases, PasswordUtils.
class
);
}
}
- 上面这段程序使用到了两个反射方法:getDeclaredMethods()和getAnnotation(),他们都属于AnnotatedElement接口。getAnnotation()方法返回指定类型的注解对象,也就是UseCase
- 注解元素可用的类型:
- 所有基本类型
- String
- Class
- enum
- Annotation
- 以上类型的数组