java自定义注解学习

时间:2021-02-23 05:46:50

很多的类库和框架都用到了java的Annotation(注解),所以今天来学习一下怎么自定义注解。
一、Annotation的分类
1、标准注解:@Override, @Deprecated, @SuppressWarnings,这是java自带的注解
2、元注解:@Retention, @Target, @Inherited, @Documented,这是用来定义注解的注解
3、自定义注解,用元注解来自定义注解
二、元注解说明
(一)Target:定义注解的作用目标
例1:

@Target(ElementType.METHOD) //这个注解只能用在方法上
@Target({ElementType.FIELD,ElementType.METHOD})//这个注解只能用在属性和方法上

未定义Target则表示可以随便用在哪儿
(二)Retention:定义注解的保留策略
例如:

@Retention(RetentionPolicy.SOURCE)//编译前解析,注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS)// 编译时解析,默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
@Retention(RetentionPolicy.RUNTIME)// 运行时解析,注解会在class字节码文件中存在,在运行时可以通过反射获取到

(三)Documented :是否会保存到 Javadoc 文档中

@Documented

(四)Inherited:父类的注解能否被子类继承

@Inherited

三、自定义注解方式
下面定义一个可以用在属性和方法上的注解,标注了这个注解之后,程序运行时会打印该属性或方法的名字,还有作者,年龄。

@Documented
@Retention(RetentionPolicy.RUNTIME)//运行时解析
@Target({ElementType.FIELD,ElementType.METHOD})//可以用在属性和方法上
@Inherited
public @interface PrintInfo
{

String author() default "未定义";
int age() default -1;
}

上面的author和age都是方法名,注解的方法定义有以下规则
a. 所有方法没有方法体,没有参数没有修饰符,实际只允许 public & abstract 修饰符,默认为 public,不允许抛异常
b. 方法返回值只能是基本类型,String, Class, annotation, enumeration 或者是他们的一维数组
c. 若只有一个默认属性,可直接用 value() 函数。一个属性都没有表示该 Annotation 为 Mark Annotation
d.方法后面default是默认返回值
下面使用一下这个注解:

public class Person
{

@PrintInfo(author = "zsj",age = 22)
private String name;
@PrintInfo(author = "jsz",age = 33)
public String getName()
{
return name;
}
}

四、注解的解析
注解的解析就是对注解的处理,注解的解析有两种方式,一是编译时的注解解析,二是运行时的注解解析。
编译时的注解解析是编译器自动进行的,他会查找所有继承自 AbstractProcessor 的类,然后调用他们的 process 方法去处理注解,但是我没有成功,下面是错误的例子……仅供参考

@SupportedAnnotationTypes(
{ "annotation.PrintInfo" })
public class PrintInfoProcessor extends AbstractProcessor
{

@Override
public boolean process(Set<? extends TypeElement> annotations,
RoundEnvironment roundEnv)
{
//annotations是PrintInfo支持的所有元素类型集合
for (TypeElement te : annotations)
{
//这里得到的是te类型的所有被PrintInfo注解过的元素
Set<? extends Element> elementSet = roundEnv
.getElementsAnnotatedWith(te);
for (Element e : elementSet)
{
Main.println(e.getSimpleName());
}
}
return true;
}
}

运行时注解的解析是通过反射来实现的,这个我倒是成功了:

    public static void main(String[] args)
{
try
{
Class<?> personClass = Class.forName("annotation.Person");
Field[] fields = personClass.getDeclaredFields();
Method[] methods = personClass.getDeclaredMethods();
for(Field field:fields)
{
PrintInfo printInfo = field.getAnnotation(PrintInfo.class);
if(printInfo != null)
println("作者是"+printInfo.author()
+"年龄是"+printInfo.age()
+"属性名:"+field.getName());
}
for(Method m:methods)
{
PrintInfo printInfo = m.getAnnotation(PrintInfo.class);
if(printInfo != null)
println("作者是"+printInfo.author()
+"年龄是"+printInfo.age()
+"方法名"+m.getName());
}
} catch (ClassNotFoundException e)
{
e.printStackTrace();
}
}

运行的结果:

作者是zsj年龄是22属性名:name
作者是jsz年龄是33方法名getName

编译时解析的注解没有定义成功,我也不知道是什么原因,以后弄懂了再回来修改这篇博客~