Java Annotation注解

1 Java 元注解

元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:

  • 1.@Target,
  • 2.@Retention,
  • 3.@Documented,
  • 4.@Inherited

这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。

@Target

@Target说明了Annotation所修饰的对象范围,默认可以使用在任何地方:

用法 使用范围
@Target(ElementType.METHOD) 用于方法
@Target(ElementType.TYPE) 用于类或者接口
@Target(ElementType.ANNOTATION_TYPE) 用于注解类型(被@interface修饰的类型)
@Target(ElementType.CONSTRUCTOR) 用于构造方法
@Target(ElementType.FIELD) 用于域
@Target(ElementType.LOCAL_VARIABLE) 用于局部变量
@Target(ElementType.PACKAGE) 记录java文件的package信息
@Target(ElementType.PARAMETER) 用于参数

在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

@Retention

@Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

取值(RetentionPoicy)有:

取值 有效范围
@Retention(RetentionPolicy.SOURCE) 在源文件中有效(即源文件保留)
@Retention(RetentionPolicy.CLASS) 在class文件中有效(即class保留)
@Retention(RetentionPolicy.RUNTIME) 在运行时有效(即运行时保留)

Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理。

@Documented

@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。

@Inherited

@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类

注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

自定义注解

下面写一个从*.properties文件中读取配置,来演示如何开发一个自定义注解。

我们需要定义两个注解,第一个用来从路径中读取配置文件*.properties定义为@Source,第二个用来给变量赋值,定义为@Value

Source.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME) //在运行时有效
@Target(ElementType.TYPE) //用于类或者接口
public @interface Source {
  String value() default "src/main/resources/*.properties";
}

Value.java

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)//在运行时有效
@Target(ElementType.FIELD)//用于域
public @interface Value {
  String value();
}

下面演示如何工作。

test-annotation.properties

hello=annotation

TestAnnotation.java

//使用@Source标记配置文件来源
@Source(value = "src/main/resources/test-annotation.properties")
public class TestAnnotation {
    //使用@Value标记读取的属性
    @Value(value = "hello")
    public static String hello;


    public static void main(String[] args) {
        AnnotationWork.work(TestAnnotation.class);

        System.out.println(hello);
    }
}

结果为

annotation

重点就在于AnnotationWork.load(TestAnnotation.class);这行。

AnnotationWork.java

import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.Properties;

public class AnnotationWork {
    public static void work(Class clazz){
        if(clazz.isAnnotationPresent(Source.class)){//判断class是否有@Source注解
            String propertiesSource = ((Source) clazz.getAnnotation(Source.class)).value();
            try {
                Properties properties = new Properties();
                properties.load(new FileReader(propertiesSource));
                Field[] fields = clazz.getDeclaredFields();
                for (Field field : fields) {
                    if(field.isAnnotationPresent(Value.class)) {//判断属性属否有@Value注解
                        String fieldKey = field.getAnnotation(Value.class).value();
                        field.set(clazz.newInstance(), properties.get(fieldKey));
                    }
                }
            }catch (IOException | IllegalAccessException | InstantiationException e){
                e.printStackTrace();
            } 
        }
    }
}

代码用反射的方法给hello赋予了初始值。

你可能感兴趣的:(Java Annotation注解)