1、注解的定义
注解为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。它是对来自像C#之类的其他语言对Java造成的语言特性压力所做出的一种回应。
注解提供了一条与程序元素关联任何信息或者任何元数据的途径。从某些方面看,注解就像修饰符一样被使用,并应用于包、类型、构造方法、方法、成员变量、参数、本地变量的声明中。这些信息被存储在注解的“name=value”结构对中。 注解类型是一种接口,能够通过java反射API的方式提供对其信息的访问。
2、Java SE5内置的注解
@Deprecated:用该注解注释的程序元素,表明不鼓励程序员使用这样的元素,通常是它很危险或存在更好的选择。
@Override:表明当前的方法定义将覆盖超类中的方法。
@SuppressWarnings:表明关闭不当的编译器警告信息。
还有四种元注解专门负责新注解的创建。
3、元注解
@Target |
表示该注解可以用与生命地方。可能的参数是一个ElementType类型,包括: CONSTRUCTOR:构造器的声明 FIELD:域的声明 LOCAL_VARIABLE:局部变量声明 METHOD:方法声明 PACKAGE:包声明 PARAMETER:参数声明 TYPE:类、接口(包括注解类型)或者enum类型
|
@Retention |
表示需要在什么级别保存该注解信息。可选的RetentionPolicy参数包括: SOURCE:注解将被编译器丢弃 CLASS:注解在class文件中可用,但会被JVM丢弃 RUNTIME:JVM将在运行期间保留改注解,因此可以用过反射机制读取注解的信息 |
@Documented |
将此注解包含在javadoc中 |
@Inherited |
允许子类继承父类中的注解 |
4、自定义注解
注解的定义看起来很像接口的定义,具体代码如下:
package annotayion;
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";
}
这里定义了一个注解UserCase ,它包含两个元素,id和description,元素的定义类似于方法,description方法有个默认值。
@Target(ElementType.METHOD)表示这个注解是用于方法的,@Retention(RetentionPolicy.RUNTIME)表示这个是运行时都可用。
接下来简单使用该注解构造一个工具类用于密码的验证。
package annotayion;
import java.util.List;
public class PasswordUtils {
@UserCase(id=47, description = "密码必须包含一个数字")
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 = "新的密码等于旧密码")
public boolean checkForNewPassword(List<String> prevPasswords, String password) {
return !prevPasswords.contains(password);
}
}
最后利用反射,我们可以从类中获取这些注解,打印出其中的参数信息:
package annotayion;
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 user 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);
}
}
5、注解元素
注解元素可以使用的类型如下:
1)所有基本类型(int,float,boolean等)
2)String
3)Class
4)Enum
5)Annotation
6)以上类型的数组
如果使用了其他类型,编译器就会报错。不允许使用任何包装类型。注解也可以作为元素的类型,也就是说注解可以嵌套。
6、默认值限制
编译器规定,注解的元素不能有不确定的值,也就是说,元素必须要么具有默认值,要么在使用注解的时候提供元素的值。
对于非基本类型的元素,无论是在源代码中声明时,还是在注解接口中定义默认值时,都不能以null作为值。