如果Java SE提供的11内置注解不能满足你的需求,可以自定义注解,注解本质是一种接口,它 是java.lang.annotation.Annotation接口的子接口,是引用数据类型。
一、声明注解
声明自定义注解可以使用@interface关键字实现,最简单形式的注解示例代码如下:
public @interface Marker{
}
上述代码声明一个Marker注解,@interface声明一个注解类型,它前面的访问限定修饰符与类一样有两 种:公有访问权限和默认访问权限。
Marker注解中不包含任何的成员,这种注解称为标记注解(Marked Annotation),基本注解中的 @Override就属于标记注解。根据需要注解中可以包含一些成员,示例代码如下:
//单值注解
@interface MyAnnotation {
String value();
}
代码中声明MyAnnotation 注解,它有一个成员value,注意value后面是有一对小括号,value前面的是 数据类型。成员也可以有访问权限修饰符,但是只能是公有权限和默认权限。
注解中的成员也可以有默认值,示例代码如下:
//带有默认值注解
@interface MyAnnotation1 {
String value() default "注解信息";
int count() default 0;
}
通过关键字default指定默认值。使用这些注解示例代码如下:
@Marker
public class HelloWorld {
@MyAnnotation(value = "Annotation")
private String info = "";
@MyAnnotation1(count = 10)
public static void main(String[] args) {
}
}
默认情况下注解可以修饰任意的程序元素(类、接口、成员变量、成员方法和数据类型等)。
二、使用元注解案例
上面声明注解只是最基本形式的注解,对于复杂的注解可以在声明注解时使用元注解。下面通过一 个案例介绍一下在自定义注解中使用元注解,在本案例中定义了两个注解。
先看看第一个注解MyAnnotation,它用来修饰类或接口,MyAnnotation代码如下:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Documented;
import java.lang.annotation.Target;
@Documented
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String description();
}
第二个注解MemberAnnotation,它用来类中成员变量和成员方法,MemberAnnotation代码如下:
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface MemberAnnotation {
Class<?> type() default void.class;
String description();
}
使用了MyAnnotation和MemberAnnotation注解是Person类,Person类代码如下:
@MyAnnotation(description = "这是一个测试类")
public class Person {
@MemberAnnotation(type = String.class, description = "名字")
private String name;
@MemberAnnotation(type = int.class, description = "年龄")
private int age;
@MemberAnnotation(type = String.class, description = "获得名字")
public String getName() {
return name;
}
@MemberAnnotation(type = int.class, description = "获得年龄")
public int getAge() {
return age;
}
@MemberAnnotation(description = "设置姓名和年龄")
public void setNameAndAge(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
使用注解时如果当前类与注解不在同一个包中,则需要将注解引入。
三、读取运行时注解信息案例
注解是为工具读取信息而准备的。有些工具可以读取源代码文件中的注解信息;有的可以读取字节码 文件中的注解信息;有的可以在运行时读取注解信息。但是读取这些注解信息的代码都是一样的,区 别只在于自定义注解中@Retention的保留策略不同。
读取注解信息需要反射相关API,Class类如下方法:
- A getAnnotation(Class annotationClass):如果此元素存在 annotationClass类型的注解,则返回注解,否则返回null。
- Annotation[] getAnnotations():返回此元素上存在的所有注解。
- Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注解。与getAnnotations() 区别在于该方法将不返回继承的注释。
- boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):如果此元素上存在 annotationClass类型的注解,则返回true,否则返回false。
- boolean isAnnotation():如果此Class对象表示一个注解类型则返回true。
在运行时Person类中注解信息代码如下:
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class HelloWorld {
public static void main(String[] args) {
try {
Class<?> clz = Class.forName("xxx.Person");
// 读取类注解
if (clz.isAnnotationPresent(MyAnnotation.class)) {
MyAnnotation ann = (MyAnnotation)clz.getAnnotation(MyAnnotation.class);
System.out.printf("类%s,读取注解描述: %s \n", clz.getName(), ann.description());
}
// 读取成员方法的注解信息
Method[] methods = clz.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(MemberAnnotation.class)) {
MemberAnnotation ann = method.getAnnotation(MemberAnnotation.class);
System.out.printf("方法%s,读取注解描述: %s \n", method.getName(), ann.description());
}
}
// 读取成员变量的注解信息
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(MemberAnnotation.class)) {
MemberAnnotation ann = field.getAnnotation(MemberAnnotation.class);
System.out.printf("成员变量%s,读取注解描述: %s \n", field.getName(), ann.description());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果如下:
类com.a51work6.Person,读取注解描述: 这是一个测试类
方法getName,读取注解描述: 获得名字
方法getAge,读取注解描述: 获得年龄
方法setNameAndAge,读取注解描述: 设置姓名和年龄
成员变量name,读取注解描述: 名字
成员变量age,读取注解描述: 年龄
以上内容仅供参考学习,如有侵权请联系我删除!
如果这篇文章对您有帮助,左下角的大拇指就是对博主最大的鼓励。
您的鼓励就是博主最大的动力!