1.自定义注解的格式
通过查看源码,可以发现任何一个注解类都有如下特征:
定义一个注解的格式:
例如:
@Target(value = {ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Id {
public String value() defult "";
}
抽象出来就是:
元注解
public @interface 注解名{
定义体;
}
看一下@UiThread源码:
@Documented
@Retention(CLASS)
@Target({METHOD,CONSTRUCTOR,TYPE})
public @interface UiThread {
}
2.常见元注解
定义:用来描述注解类属性的注解。
作用:主要用来描述注解类的一些属性。
常见的元注解:
① @Target:描述注解的使用范围,注解可以用到的地方
取值:
CONSTRUCTOR:构造器
FIELD:成员变量定义
LOCAL_VARIABLE:局部变量
METHOD:方法
PACKAGE:包
PARAMETER:参数
TYPE:类,接口(包括注解类型)enum声明
② @Retention:表示需要在什么级别保存该注解信息,用与描述注解的生命周期,即被描述的注解在什么范围内有效
取值:
SOURCE:SOURCE源文件中有效,及原文件保留;
CLASS:在class文件中有效,及class保留
RunTIME时有效,运行时保留
③ Documented:一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中
④ @Inherited:描述某个被标注的类型是可被继承的
3.注解参数可支持的数据类型
1、所有基本数据类型(int,float,boolean,byte,double,char,long,short);
2、String类型;
3、Class类型;
4、enum类型;
5、Annotation类型;
6、以上所有类型的数组
4.注解处理器
我们定义注解的目的就是为了使用注解,所以我们就需要创建一个用于解读注解的注解处理器。
Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。
对于自定义的注解类我们需要关心Java在java.lang.reflect 包下新增的AnnotatedElement接口,该接口代表我们的注解可以应用的地方
该接口主要有如下几个实现类:
java.lang.reflect 包下主要包含一些实现反射功能的工具类,实际上,java.lang.reflect 包所有提供的反射API扩充了读取运行时Annotation信息的能力。当一个Annotation类型被定义为运行时的Annotation后,该注解才能是运行时可见,当class文件被装载时被保存在class文件中的Annotation才会被虚拟机读取。
AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下四个个方法来访问Annotation信息:
5.自定义注解使用:
FruitCatory.java
/**
*第一步:定义注解类
* Created by dkp on 2019/6/7.
* 定义一个水果类型的注解
* 步骤:
* 1.创建类用@interface修饰
* 2.用元数据Target描述注解的使用方位
* 3.用@Retention描述该注解生效范围
* 以上是必须添加的元数据,下面是根据需求可自己配置的元数据
* @Documented 一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中
* @Inherited:描述某个被标注的类型是可被继承的
*/
@Target(value={ElementType.METHOD,ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface FruitCatory {
String value() default "";
}
FruitColor.java
/**
* Created by dkp on 2019/6/7.
* 定义一个水果颜色的注解
* 步骤:
* 1.创建类用@interface修饰
* 2.用元数据Target描述注解的使用方位
* 3.用@Retention描述该注解生效范围
* 以上是必须添加的元数据,下面是根据需求可自己配置的元数据
* @Documented 一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中
* @Inherited:描述某个被标注的类型是可被继承的
*/
@Target(value={ElementType.METHOD,ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface FruitColor {
public enum Color{BLUE,RED,YELLOW};
public Color fruitColor() default Color.RED;
}
FruitProvider.java
/**
* Created by dkp on 2019/6/7.
* 定义一个水果提供商的注解
* 步骤:
* 1.创建类用@interface修饰
* 2.用元数据Target描述注解的使用方位
* 3.用@Retention描述该注解生效范围
* 以上是必须添加的元数据,下面是根据需求可自己配置的元数据
* @Documented 一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中
* @Inherited:描述某个被标注的类型是可被继承的
*/
@Target(value={ElementType.METHOD,ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface FruitProvider {
int providerId() default 0;
String providerName() default "";
String providerAddress() default "";
}
在类中使用注解
package com.dkp.viewdemo.Annotation;
/**
* Created by dkp on 2019/6/7.
* 第二步:注解使用
*/
public class Fruit {
@FruitCatory("苹果")
private String fruitCatory;
@FruitColor(fruitColor = FruitColor.Color.YELLOW)
private String fruitColor;
@FruitProvider(providerId = 1,providerName = "烟台富士",providerAddress = "山东省烟台市富士苹果园")
private String providerdes;
public String getFruitCatory() {
return fruitCatory;
}
public void setFruitCatory(String fruitCatory) {
this.fruitCatory = fruitCatory;
}
public String getFruitColor() {
return fruitColor;
}
public void setFruitColor(String fruitColor) {
this.fruitColor = fruitColor;
}
public String getProviderdes() {
return providerdes;
}
public void setProviderdes(String providerdes) {
this.providerdes = providerdes;
}
}
定义注解解析器
/**
* Created by dkp on 2019/6/7.
* 定义一个注解处理器,解读我们定义的注解
*/
public class AnnotationProcessor {
public static void getFruitInfo(Class> clazz){
String strFruitName=" 水果名称:";
String strFruitColor=" 水果颜色:";
String strFruitProvicer="供应商信息:";
Field[] fields = clazz.getDeclaredFields();
for (Field field :fields){
//从打印信息可以看到getDeclaredFields返回的是clazz类中用到注解的成员变量的集合。
System.out.println("field name ="+field.getName()+",fields.DeclaringClass = "+field.getDeclaringClass());
}
for(Field field :fields){
//判断该程序元素上是否包含指定类型的注解
if(field.isAnnotationPresent(FruitCatory.class)){
FruitCatory fruitName = (FruitCatory) field.getAnnotation(FruitCatory.class);
strFruitName=strFruitName+fruitName.value();
System.out.println(strFruitName+"do something ...");
}
else if(field.isAnnotationPresent(FruitColor.class)){
FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class);
strFruitColor=strFruitColor+fruitColor.fruitColor().toString();
System.out.println(strFruitColor+"do something ...");
}
else if(field.isAnnotationPresent(FruitProvider.class)){
FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class);
strFruitProvicer=" 供应商编号:"+fruitProvider.providerId()+" 供应商名称:"+fruitProvider.providerName()+" 供应商地址:"+fruitProvider.providerAddress();
System.out.println(strFruitProvicer+"do something ...");
}
}
}
}
写个测试程序试验一下:
public class AnnotationTest {
public static void main(String[]arg){
AnnotationProcessor.getFruitInfo(Fruit.class);
}
}
打印结果:
field name =fruitCatory,fields.DeclaringClass = class com.dkp.viewdemo.Annotation.Fruit
field name =fruitColor,fields.DeclaringClass = class com.dkp.viewdemo.Annotation.Fruit
field name =providerdes,fields.DeclaringClass = class com.dkp.viewdemo.Annotation.Fruit
水果名称:苹果do something ...
水果颜色:YELLOWdo something ...
供应商编号:1 供应商名称:烟台富士 供应商地址:山东省烟台市富士苹果园do something ...
Process finished with exit code 0
至此,自定义注解完成。
如果对注解概念不明白的话可以看下这篇文章:
https://blog.csdn.net/briblue/article/details/73824058