我们用过 JDK给我们提供的 @Override @Deprecated @SuppressWarning 注解 ,这些注解是JDK给我们提供的 ,我们只是在用别人写好的东西 ,那么我们是否可以自己写注解呢?当然是可以的 。
我们写的注解包括三个环节
1、 注解的声明 ,也就是注解类的定义 形式如下 @interface 来进行注解的声明
package annotate;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) //这个标识注解应该标在那里 ElementType的几个枚举值就代表了 注解应该写在的位置
@Retention(RetentionPolicy.RUNTIME) //指定了注解保留的周期
public @interface CheckString {
}
@Retention(RetentionPolicy.RUNTIME)
指定了注解保留的周期 注解的生命周期有是三个 RetentionPolicy 枚举的三个值代表了三个声明周期 默认是CLASS
枚举常量摘要 | |
---|---|
CLASS 编译器将把注释记录在类文件中,但在运行时 VM 不需要保留注释。 | |
RUNTIME 编译器将把注释记录在类文件中,在运行时 VM 将保留注释,因此可以反射性地读取。 | |
SOURCE 编译器要丢弃的注释。 |
@Target(ElementType.TYPE)
这个标识注解应该标在那里 ElementType的几个枚举值就代表了 注解应该写在的位置
CONSTRUCTOR 构造方法声明 |
FIELD 字段声明(包括枚举常量) |
LOCAL_VARIABLE 局部变量声明 |
METHOD 方法声明 |
PACKAGE 包声明 |
PARAMETER 参数声明 |
TYPE 类、接口(包括注释类型)或枚举声明 |
Annotation类型里面的参数该怎么设定:
第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;
第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
package annotate;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD) //这个标识注解应该标在那里 ElementType的几个枚举值就代表了 注解应该写在的位置
@Retention(RetentionPolicy.RUNTIME) //指定了注解保留的周期
public @interface CheckString {
/**
* 检验的正则表达式
*/
String regex() default ".*";
/**
* 字段是否需要填写
*/
Exists exists() default Exists.Skipped;
/**
* 字段最小长度
* @return
*/
int minlen() default 0;
/**
* 字段最大长度
* @return
*/
int maxlen() default Short.MAX_VALUE;
}
枚举类:
package annotate;
public enum Exists {
/**
* 跳过检验
*/
Skipped,
/**
* 禁止填写
*/
Prohibit,
/**
* 非空字段
*/
Required,
/**
* 可选字段
*/
Optional
}
注解使用类:
package model;
import annotate.CheckString;
import annotate.Exists;
public class Persion {
@CheckString(exists=Exists.Required)
public String test;
@CheckString(exists=Exists.Required)
private String name;
@CheckString(exists=Exists.Required)
private String password;
private String sex;
private int age;
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Persion [name=" + name + ", password=" + password + ", sex=" + sex + ", age=" + age + ", test=" + test + "]";
}
public Persion(String name, String password) {
super();
this.name = name;
this.password = password;
}
}
利用反射来操作注解
Class类有一个 方法
| getAnnotation(Class<A> annotationClass) |
这个方法接受一个注解的字节码参数 ,然后返回这个类所标识的注解对象 ,因为我们标识了一个注解就相当于产生了一个注解对象 。
boolean | isAnnotationPresent(Class<? extendsAnnotation> annotationClass) |
这个方法判断一个类是否被注解所标识
下面是代码示例
public class CheckParamUtil {
public static void checkParam(Object o) throws Exception{
out:{
final Class<?> objClass=o.getClass();
Field[] farray=objClass.getDeclaredFields();//获取所有字段 包括private 不包括父类字段
Class<CheckString> chkString=CheckString.class;//CheckString的class
for(int i=0;i<farray.length;i++){
Field field=farray[i];//获取其中字段
String fieldName=field.getName();//获取字段名称
if(field.isAnnotationPresent(chkString)){//判断是否被chkstring注解所标识
//如果被标识
CheckString chk=field.getAnnotation(chkString);// 返回这个类所标识的注解对象
Exists e=chk.exists(); //获取字段是否需要填写
//获得字段的值
field.setAccessible(true);//private字段要设置为true才可以获取值或者修改值
String fValue=(String) field.get(o);
if(e==Exists.Required){//如果字段是必须填写
if(fValue==null||fValue.equals("")){
//如果字段是为空
System.out.println(objClass.getSimpleName()+"."+fieldName+"必须填写");
break out;
}
}
}
}
}
}
验证:
public class TestCheckParam {
public static void main(String[] args) {
Persion p=new Persion("zhangsan","111111");
try {
CheckParamUtil.checkParam(p);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
控制太打印:Persion.test必须填写