java_notation.html
Java Annotation 注解
注解:
是Java代码中的元数据, 在创建之后的某个时刻可以使用, 代表了代码的配置信息, 代码和配置结合在一起, 存储有关程序的额外信息.
定义注解:
注解的定义类似interface的定义, 同其他Java接口一样, 注解也会被编译成class文件. 格式为:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.Runtime)
public @interface Test{
///
public int id();
public String descripteion() default "no description";
}
其中, @Target
和 @Retention
也是注解被称为元注解, 是Java提供的四种注解,后面会补充.@Target
代表了该注解应用的对象(如一个类或者一个函数).@Retention
代表了该注解在哪一个级别可用(共三种: 源码中Source, 类文件Class, 运行时Runtime).
一般的注解中会有元素, 元素的定义类似于接口中方法的定义(成员变量类似接口的方法的定义). 但是后面可以跟一个default指定默认值.
没有元素的注解称之为标记注解, 如元注解中的 @Documented
注解的元素使用时是以名-值对的形式定义的, 并放在注解后的括号内, 如@Test( id = 49, desctiption = "lyb" )
.
元注解:
元注解是Java源码中定义的四种注解, 自己定义的注解必然要借助这四种注解.
注解 | 解释 |
---|---|
@Target | 表示该注解可以用于什么地方, 接受的参数为ElementType参数, 共有以下几种类型: CONSTRUCTOR: 构造器的声明 FIELD: 域声明(包括enum实例) LOCAL_VARIABLE: 局部变量声明 METHOD: 方法声明 PACKAGE: 包声明 PARAMETER: 参数声明 TYPE: 类, 接口(包括注解类型)或enum声明 |
@Retention | 表示需要在什么级别保存该注释信息, 接受参数为RetentionPolicy类型: SOURCE: 注解将被编译器丢弃 CLASS: 注解在class文件中可用,但是会被编译器丢弃 RUNTIME: VM将在运行期也保留注解, 因此可以通过反射机制读取注解的信息 |
@Documented | 将此注解包含在Javadoc中 |
@Inherited | 允许子类继承父类中的注解 |
元注解本身的定义也是依赖元注解的, 类似于递归.
如 @Target
的源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
注解解释器:
注解和注释的区别: 如果没有处理注解的工具, 那么注解不会比注释更有用. 所以使用注解就是要有相应的注解处理器, 而注解处理器是建立在反射机制上的.
对以VM, 在没有注解处理器的情况下, 有没有注解对于源代码编译得到的字节吗应该是一样的, 当然可能会多出注解的字节码.
下面给出一个例子:
注解UserCase:
package test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by lyb on 16-11-29.
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserCase {
public int id();
public String description() default "no description";
}
使用了注解的一般类:
package test;
import java.util.List;
/**
* Created by lyb on 16-11-29.
*/
public class PasswordUtil {
@UserCase(id = 47, description = "Passwords must contains at last one numberic")
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 = 50, description = "New passwords can't equals the used one")
public boolean checkForNewPassword(List<String> prevPassword, String password){
return !prevPassword.contains(password);
}
}
真正的注解处理器:
package test;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Created by lyb on 16-11-29.
*/
public class UserCaseTracker {
public static void trackUserCases(List<Integer> userCases, Class<?> cl){
for (Method m : cl.getDeclaredMethods()){
UserCase uc = m.getAnnotation(UserCase.class);
if (uc != null){
System.out.println("Found user case : " + uc.id()
+ " " + uc.description());
userCases.remove(new Integer(uc.id()));
}
}
for (int i : userCases){
System.out.println("Warning: Missing user case !");
}
}
public static void main(String[] args){
List<Integer> userCases = new ArrayList<>();
Collections.addAll(userCases, 47, 48, 49, 50);
trackUserCases(userCases, PasswordUtil.class);
}
}
程序的输出:
Found user case : 47 Passwords must contains at last one numberic
Found user case : 48 no description
Found user case : 50 New passwords can't equals the used one
Warning: Missing user case-49!
需要注意的地方,
-
传给反射的参数是class类型的.
-
因为
@UserCase
修饰的是Method, 所以通过Method得到注解对象.
注解元素的类型:
即在注解的interface中定义的类似函数的元素, 如int的id(), String的description().
所有可用的注解元素的类型有:
- 所有基本类型(int, float, boolean)等
- String
- class
- enum
- Annotation
- 以上类型的数组
需要注意的是:
- 不能使用任何包装类型
- 注解可以嵌套
对注解元素的限制:
注解中的元素都必须确定, 或者有默认值, 或者在注解中赋值.
非基本类型(如自己定义的类)的值不能有null, 因此必须自己定义一些特殊值来表示某个元素不存在.
使用多个注解的时候, 同一个注解不能重复使用.
注解本身不支持继承, 但是被 @Inherited
修饰的类具有继承性. 同样地, 由于没有继承性, 因此要具有类似多态的注解, 就必须多定义不同参数的函数或者是类, 并且用反射函数 getDeclaredAnnotation()
来遍历得到需要的注解.
generated by haroopad