目录
@Documented(注解是否应该出现在JavaDoc文档中)
小结:Java自定义注解就是使用@interface定义功能,结合使用jdk元注解标注作用域等,在程序运行过程使用反射获取注解的值的过程。
在知道自定义注解如何使用时需要先知道jdk的元注解含义。
jdk的元注解
元注解是用来修饰注解的注解,通常用于注解的定义。
元注解是Java语言中的特殊类型注解,用于修饰其他普通注解。元注解不仅可以为注解赋予合适的含义,而且还可以在使用注解时发挥限制和规范作用。
Java提供了四种元注解,分别是:
-
@Retention:指定了被修饰的注解的有效范围,包括SOURCE、CLASS和RUNTIME三种,它们分别代表了在源代码中有效、在编译时有效和在运行时有效。
注:反射使用时获取值只能在RUNTIME时有效,其他两种情况获取为空。 -
@Target:指定了被修饰的注解可以存在的位置,包括METHOD、FIELD、TYPE等多种。
-
@Inherited:表示被修饰的注解可以被继承。
-
@Documented:表示被修饰的注解将会出现在文档中。
@Retention(注解的生命周期)
@Retention:指定注解的生命周期,有三种选项:
- RetentionPolicy.SOURCE:注解仅存在于源代码中,在编译后会被丢弃,不会出现在class文件中和运行时环境中。
- RetentionPolicy.CLASS:注解会被保留到编译后的class文件中,在程序运行时不会被加载。这也是默认值。
- RetentionPolicy.RUNTIME:注解会在运行时加载并保留,可以通过反射机制读取。
使用@Retention注解常见的方式为:
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
// Annotation definition here
}
@Target(注解的作用目标)
@Target是Java中的一个元注解,用于指定所修饰的注解可以应用于哪些程序元素上。这个注解的取值包括:
-
ElementType.ANNOTATION_TYPE:可以用于注解其他的注解。
-
ElementType.CONSTRUCTOR:可以用于构造器。
-
ElementType.FIELD:可以用于字段(成员变量)。
-
ElementType.LOCAL_VARIABLE:可以用于局部变量。
-
ElementType.METHOD:可以用于方法。
-
ElementType.PACKAGE:可以用于包定义。
-
ElementType.PARAMETER:可以用于方法形参。
-
ElementType.TYPE:可以用于类、接口、枚举、注解类型等。
常用的也就加粗的三种,例如,我们定义一个名为MyAnnotation的自定义注解,并希望只能够将它应用于类上:
@Target(ElementType.TYPE)
public @interface MyAnnotation {
// Annotation definition here
}
通过@Target指定了MyAnnotation的目标类型为ElementType.TYPE,表示它仅可以用于类、接口、枚举等类型上。如果我们在类、方法或其他不允许的程序元素上使用该注解,则会得到编译器错误。
@Documented(注解是否应该出现在JavaDoc文档中)
@Documented是Java中的一个元注解,用于指定被修饰的注解应该被包含在文档中。当一个注解使用了@Documented元注解时,在通过javadoc工具生成API文档时,注解信息将会被包含进去。
下面是一个简单的例子,展示了如何使用@Documented元注解:
@Documented
public @interface MyAnnotation {
// Annotation definition here
}
在上面的代码中,我们定义了一个名为MyAnnotation的自定义注解,并在它上面添加了@Documented元注解。这意味着在程序生成的API文档中,使用了MyAnnotation注解的方法将会包含注解信息。
使用@Documented元注解可以帮助开发者在文档中更清晰地记录和描述使用的注解的作用和实现方式。不过需要注意的是,并不是所有的注解都适合使用@Documented元注解,需要根据实际情况进行考虑。
@Inherited(是否允许子类继承注解)
@Inherited是Java中的一个元注解,用于指定被修饰的注解是否可以被继承。当一个注解使用了@Inherited元注解时,它将会被继承到子类中。
下面是一个简单的例子,展示了如何使用@Inherited元注解:
@Inherited
public @interface MyAnnotation {
// Annotation definition here
}
在上面的代码中,我们定义了一个名为MyAnnotation的自定义注解,并在它上面添加了@Inherited元注解。这意味着如果一个类A使用了注解MyAnnotation,并且类B继承自类A,则类B也将会具有注解MyAnnotation。
需要注意的是,要使@Inherited元注解生效,被继承的注解必须具有RUNTIME级别的@Retention元注解。此外,在实际使用时需要小心,不一定所有的注解都需要或适合被继承。
自定义注解的使用示例
定义
import java.lang.annotation.*;
//标注作用目标是类,方法,字段上,多个作用目标时用逗号隔开
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
//标注生成注释
@Documented
//标注运行时有效
@Retention(RetentionPolicy.RUNTIME)
//标注可以被继承
@Inherited
public @interface MyAnnotation {
String value() default "test";
int age() default 18;
}
测试
import com.wzw.annotation.annotation.MyAnnotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@MyAnnotation(value = "wwy",age = 27)
public class TestAnnotation {
@MyAnnotation(age = 33)
String string = "test";
@MyAnnotation(value = "wwe")
public void test(){
System.out.println(string);
}
public static void main(String[] args) {
try {
//获取类上的注解
MyAnnotation annotation = TestAnnotation.class.getAnnotation(MyAnnotation.class);
String name = annotation.value();
int age = annotation.age();
System.out.println(name+":"+age);
//获取方法上的
Method test = TestAnnotation.class.getMethod("test");
MyAnnotation annotation1 = test.getAnnotation(MyAnnotation.class);
String name1 = annotation1.value();
int age1 = annotation1.age();
System.out.println(name1+":"+age1);
//获取字段上的
Field string = TestAnnotation.class.getDeclaredField("string");
MyAnnotation annotation2 = string.getAnnotation(MyAnnotation.class);
String name2 = annotation2.value();
int age2 = annotation2.age();
System.out.println(name2+":"+age2);
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果: