关于Java 自定义注解中的参数的使用举例说明

610 阅读3分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

注解中的参数是什么

我们在开发的时候,对于经常使用到的注解,其实是有“属性”这个概念的。

举例来说,在使用Spring 的时候,最常用的@Autowire 注解,我们看一下这个注解的定义:

@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {

   /**
    * Declares whether the annotated dependency is required.
    * <p>Defaults to {@code true}.
    */
   boolean required() default true;

}

关于这个注解,我们可以选择是否使用required 参数。

在java 中,所有的注解的定义大致结构都是很相似的。

在我们自定义注解的过程中,就少不了和注解参数打交道。一切没有参数的注解其实都是没有什么意义的。对于注解参数的定义,我们在之前的文章介绍了很多,但是却没有说明定义了的注解的参数如何使用。

那么接下来,我们就来介绍一些自定义注解参数的使用方法及使用场景。

注解参数的使用方法

在自定义注解的时候,我们有一点需要着重注意,那就是在设置参数的时候,是可以设置默认值的。

但是如果没有为这个参数设置默认值,那么在使用这个注解的时候,必须要为没有默认值的参数赋值。

如果想要使用这个参数,那么就是需要利用java 的反射机制。

我们这里直接举一个实例来看如何使用注解+注解的参数+反射,来完成自定义的业务逻辑。

我们分别定义三个注解,这三个注解的target 分别为属性、方法、类。具体定义如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FiledAnnotationExample {
    String value() default "field default value";   
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodAnnotationExample {
    String value() default "method default value";
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TypeAnnotationExample {
    String value() default "class default value";	
}

三个不同类型的注解定义好了,我们接着来定义一个目标类,并将注解应用到其合适的位置。

@TypeAnnotationExample(value = "class real value")
public class Student {
 
    @FiledAnnotationExample(value = "field real value")
    private String name = "";
 
    @MethodAnnotationExample()
    public String getDefaultValue() {
	return "from get default value method";
    }
 
    @MethodAnnotationExample("method real value")
    public String getSelfDefineValue() {
	return "from get self define method";
    }
}

然后定义一个类主类,来展示自定义注解的效果。

public class TestMain {
	
    public static void main(String[] args) throws Exception {
		
        Class clazz = Class.forName("com.xxx.xxx.Student");
        
        // 首先来判断Student 类上是否有标注TypeAnnotationExample 注解
        boolean flag = clazz.isAnnotationPresent(类上是否有标注TypeAnnotationExample.class);
        
        //  上面的答案是显然的,然后获取Student 类上标注的TypeAnnotationExample 注解中的值
        if (flag) {
            // 在这里面可以做一些自己定义的逻辑,这里只打印出这个注解内的值
            TypeAnnotationExample typeAnnotation = (TypeAnnotationExample) clazz.getAnnotation(TypeAnnotationExample.class);
            System.out.println("the value in Student class annotation: " + typeAnnotation.value());
        }
        
        
        // 然后我们来看一下属性上注解的值的获取
        // 通过反射,来访问Student 类的所有字段
        for (Field field : clazz.getDeclaredFields()) {
            // 获取各个属性上的注解
            FiledAnnotationExample filedAnnotation = field.getAnnotation(FiledAnnotationExample.class);
            System.out.println( "field name: " + field.getName());
            System.out.println("the value in Student field annotation: " + filedAnnotation.value());
        } 
        
        
        // 最后我们来看一下方法上注解的使用
        List<Method> list = new ArrayList<Method>();
        // 通过反射获取Student 类中的所有方法
        Method[] method = clazz.getMethods();
        for (int i = 0; i < method.length; i++) {
            list.add(method[i]);
        }
        
        for (Method m : list) {
        	MethodAnnotationExample methodAnnotation = m.getAnnotation(MethodAnnotationExample.class);
            if (methodAnnotation == null)
                continue;
            System.out.println( "method name:" + m.getName());
            System.out.println("name of annotation in method = " + methodAnnotation.name());
        }
    }
}

总结

这篇文章的目的就是带读者进入自定义注解+注解参数+反射的使用基本流程中。其实后续的使用参照这个例子,总是会有一些借鉴的。