注解有2个很基础的属性:
- @Target(作用对象)
- @Retention(保留策略)
@Retention保留策略:
- @Retention(RetentionPolicy.SOURCE):保留到源码阶段,在编译成class文件时丢弃,不会保留到class文件中;需要注意的是,在编译器处理期间源码注解还存在,编译器处理完之后就没有该注解信息了;
- @Retention(RetentionPolicy.CLASS):保留到编译阶段,会被vm丢弃
- @Retention(RetentionPolicy.RUNTIME):保留到运行时;一般自定义注解,会选择使用RUNTIME配合反射使用;
@Target作用对象:
- @Target(ElementType.TYPE) 作用于:class,interface,enum,annotation(常用)
- @Target(ElementType.FIELD) 作用于:字段
- @Target(ElementType.METHOD)作用于:方法
- @Target(ElementType.PARAMETER)作用于:方法的参数
- @Target(ElementType.CONSTRUCTOR)作用于:构造方法
- @Target(ElementType.LOCAL_VARIABLE)作用于:方法内的局部变量
- @Target(ElementType.ANNOTATION_TYPE)作用于:作用于注解类annotation
- @Target(ElementType.PACKAGE) 作用于包
- @Target(ElementType.TYPE_PARAMETER) 作用于类型泛型(jdk1.8加入)
- @Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型(JDK1.8加入)
有了上面2个基础的注解我们就可以自定义一个自己的注解类了;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnno {
/**
*功能:
* true:字段值不能为null,如果是int类型,就不能为0
* false:字段值可以为null
* @return
*/
boolean NOTNULL() default false;//default 默认值,如果不添加default,在使用这个注解时就必须给NOTNULL设置值;
}
只有这个注解,其实没有任何意义,这个时候注解没有功能;想要有功能就必须解析这个注解类;在RUNTIME时,可以通过反射获取到字段上面的注解类,来制定我们想要的功能;其实在编译阶段也可以解析注解,lombok注解的Retention是SOURCE,在编译期间就对注解进行了处理;(source/class这篇博客就是讲解如何在编译器处理注解;)
public class ParseMyAnno {
/**
*只处理了String类型和int类型的变量;
*
*/
public void parse(Class c,Object object ) throws IllegalAccessException {
Field[] fields = c.getFields();
for (Field field : fields) {
if(field.getAnnotation(MyAnno.class)!= null){
boolean notnull = field.getAnnotation(MyAnno.class).NOTNULL();//获取到NOTNULL的值;
Object value = field.get(object);
if(notnull){
String typeName = field.getGenericType().getTypeName();
System.out.println(typeName);
if((typeName.equals("java.lang.String") && value == null))
{
throw new NullPointerException(field.getName() + "的值为空");
}else if( typeName.equals("int") ){
Integer v = (Integer) value;
if(v == 0)
throw new NullPointerException(field.getName() +"的值为0");
}
}
}
}
}
/**
*
*在字段中使用自定义注解:MyAnno
*/
public class AnnoTest {
@MyAnno(NOTNULL = true)
public String name;
@MyAnno
public String id;
@MyAnno(NOTNULL = true)
public int number;
public AnnoTest(){}
public AnnoTest(String name) {
this.name = name;
}
public AnnoTest(String name, int number) {
this.name = name;
this.number = number;
}
}
测试1
public static void main(String[] args) throws IllegalAccessException {
ParseMyAnno parseMyAnno = new ParseMyAnno();
AnnoTest t = new AnnoTest();//name =null,number=0
parseMyAnno.parse(AnnoTest.class,t);
}
Exception in thread "main" java.lang.NullPointerException: name的值为空
at filter.at.ParseMyAnno.parse(ParseMyAnno.java:30)
at filter.at.ParseMyAnno.main(ParseMyAnno.java:46)
测试2
public static void main(String[] args) throws IllegalAccessException {
ParseMyAnno parseMyAnno = new ParseMyAnno();
AnnoTest t = new AnnoTest("name11");//number=0
parseMyAnno.parse(AnnoTest.class,t);
}
Exception in thread "main" java.lang.NullPointerException: number的值为0
at filter.at.ParseMyAnno.parse(ParseMyAnno.java:34)
at filter.at.ParseMyAnno.main(ParseMyAnno.java:49)