java_notation.htmljavascript
是Java代码中的元数据, 在建立以后的某个时刻能够使用, 表明了代码的配置信息, 代码和配置结合在一块儿, 存储有关程序的额外信息.php
注解的定义相似interface的定义, 同其余Java接口同样, 注解也会被编译成class文件. 格式为:css
@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" )
.html
元注解是Java源码中定义的四种注解, 本身定义的注解必然要借助这四种注解.java
注解 | 解释 |
---|---|
@Target | 表示该注解能够用于什么地方, 接受的参数为ElementType参数, 共有如下几种类型: CONSTRUCTOR: 构造器的声明 FIELD: 域声明(包括enum实例) LOCAL_VARIABLE: 局部变量声明 METHOD: 方法声明 PACKAGE: 包声明 PARAMETER: 参数声明 TYPE: 类, 接口(包括注解类型)或enum声明 |
@Retention | 表示须要在什么级别保存该注释信息, 接受参数为RetentionPolicy类型: SOURCE: 注解将被编译器丢弃 CLASS: 注解在class文件中可用,可是会被编译器丢弃 RUNTIME: VM将在运行期也保留注解, 所以能够经过反射机制读取注解的信息 |
@Documented | 将此注解包含在Javadoc中 |
@Inherited | 容许子类继承父类中的注解 |
元注解自己的定义也是依赖元注解的, 相似于递归.
如 @Target
的源码:node
@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();
}
注解和注释的区别: 若是没有处理注解的工具, 那么注解不会比注释更有用. 因此使用注解就是要有相应的注解处理器, 而注解处理器是创建在反射机制上的.nginx
对以VM, 在没有注解处理器的状况下, 有没有注解对于源代码编译获得的字节吗应该是同样的, 固然可能会多出注解的字节码.git
下面给出一个例子:github
注解UserCase:web
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().
全部可用的注解元素的类型有:
须要注意的是:
对注解元素的限制:
注解中的元素都必须肯定, 或者有默认值, 或者在注解中赋值.
非基本类型(如本身定义的类)的值不能有null, 所以必须本身定义一些特殊值来表示某个元素不存在.
使用多个注解的时候, 同一个注解不能重复使用.
注解自己不支持继承, 可是被 @Inherited
修饰的类具备继承性. 一样地, 因为没有继承性, 所以要具备相似多态的注解, 就必须多定义不一样参数的函数或者是类, 而且用反射函数 getDeclaredAnnotation()
来遍历获得须要的注解.
generated by haroopad