自定义注解

1.自定义注解的格式

通过查看源码,可以发现任何一个注解类都有如下特征:

  1. 注解类会被@interface标记
  2. 注解类的顶部会被@Documented、@Retention、@Target、@Inherited这四个注解标记,其中@Documented、@Inherited可选的,@Retention、@Target必须有

定义一个注解的格式:

例如:

@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接口,该接口代表我们的注解可以应用的地方

该接口主要有如下几个实现类:

  • Class:类定义
  • Constructor:构造器定义
  • Field:累的成员变量定义
  • Method:类的方法定义
  • Package:类的包定义

java.lang.reflect 包下主要包含一些实现反射功能的工具类,实际上,java.lang.reflect 包所有提供的反射API扩充了读取运行时Annotation信息的能力。当一个Annotation类型被定义为运行时的Annotation后,该注解才能是运行时可见,当class文件被装载时被保存在class文件中的Annotation才会被虚拟机读取。

AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下四个个方法来访问Annotation信息:

  • 方法1: T getAnnotation(Class annotationClass): 返回改程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null。
  • 方法2:Annotation[] getAnnotations():返回该程序元素上存在的所有注解。
  • 方法3:boolean is AnnotationPresent(Class annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false.
  • 方法4:Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注解。与此接口中的其他方法不同,该方法将忽略继承的注解。(如果没有注解直接存在于此元素上,则返回长度为零的一个数组。)该方法的调用者可以随意修改返回的数组;这不会对其他调用者返回的数组产生任何影响。

5.自定义注解使用:

  1. 定义注解类

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 "";

}
  1. 在类中使用注解

     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;
     }
    

    }

  2. 定义注解解析器

     /**
      * 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

你可能感兴趣的:(Java)