在JDK的元注解一章,虽然没有正式介绍,但是相各位已经知道,声明一个注解很简单,就是使用@interface关键字即可。接下来,我们学习如何给自己创建的注解增加一些实际的功能。
自定义注解
我们首先来看一下自定义注解的注意事项 :
- 定义注解需要使用@interface关键字,定义格式 : public @interface 注解名称,其中public是权限修饰符。
示例代码
pbulic @interface Test {}
- 使用注解很简单,只需要将注解像public,final等修饰符一样,放在程序元素的前面或者上面即可。一般会选择放在程序元素的上面。默认情况下,注解可以修饰程序中的任何元素
示例代码
@Test
public class TestAnnotation {
@Test
private String name;
@Test
public void test1() {
System.out.println("test1");
}
}
- 定义注解可以为注解声明成员变量,格式 :数据类型 成员变量名称(); 注意,跟声明方法形式很像,但这是注解的成员变量,不是方法。
- 注解中的成员变量只能是八种基本数据类型,以及String,Class,Enum等
示例代码
@interface Test {
//声明注解的成员变量 数据类型 成员变量名称();
String name();
int value();
String[] names();
}
- 使用注解的时候必须为注解中所有的成员变量赋值,否则编译报错。
示例代码
@Test(name = "小钻风", value = 300,names= {"避尘大王","避暑大王","避寒大王"})
public class TestAnnotation {
@Test(name = "小钻风", value = 300,names= {"避尘大王","避暑大王","避寒大王"})
private String name;
@Test(name = "小钻风", value = 300,names= {"避尘大王","避暑大王","避寒大王"})
public void test1() {
System.out.println("test1");
}
}
- 可以为注解的成员变量声明默认值,格式 defalut value
示例代码
@interface Test {
String name();
int value();
String[] names() default {"避尘大王","避暑大王","避寒大王"};
}
- 使用注解的时候,带默认值的成员变量可以不赋值,这个时候使用的是注解中成员变量的默认值
示例代码
@Test(name = "小钻风", value = 300)
public class TestAnnotation {
@Test(name = "小钻风", value = 300)
private String name;
@Test(name = "小钻风", value = 300)
public void test1() {
System.out.println("test1");
}
}
- 使用注解的时候,如果只需要给注解的value成员变量赋值,则成员变量名称可以省略,只赋值即可
示例代码
@Test(name = "小钻风", value = 300) //value不能省略
public class TestAnnotation {
@Test(name="小钻风",value = 300) //value不能省略
private String name;
@Test(300) //value可以省略
public void test1() {
System.out.println("test1");
}
}
@interface Test {
String name() default "小钻风";
int value();
String[] names() default { "避尘大王", "避暑大王", "避寒大王" };
}
- Java.lang.Annotation接口是所有注解的父接口,所以,注解一旦声明创建,便自动继承java.lang.Annotation接口
总结 : 根据注解是否包含成员变量,可以把注解分为两类
- 标记注解
没有定义成员变量的注解被称为标记。这种注解仅利用自身的存在与否来提供信息,例如@Override。
- 元数据注解
包含成员变量的注解可以接受更多的元数据,所以也被称为元数据注解。这种注解,其本身,其成员变量都可以用来提供信息
获取注解信息
使用注解修饰了程序元素以后,这些注解不会自己生效,必须由相应的工具类来提取并处理才能生效。这些工具类都在java.lang.reflect包中。从Java 5开始,java.lang.reflect包所提供的反射AIP增加了读取运行时注解的能力。只有当定义注解的时候使用了@Retention(RetentionPolicy.RUNTIME)修饰,该注解才会在运行时可见,JVM才会在装载.class文件时读取保存在.class文件中的注解。
示例代码
一:声明注解
@Retention(RetentionPolicy.RUNTIME)
@interface Test {
String name() default "小钻风";
int value();
String[] names() default { "避尘大王", "避暑大王", "避寒大王" };
}
二:创建测试类
@Test(name = "小钻风", value = 300) // value不能省略
public class TestAnnotation {
@Test(name = "小钻风", value = 300) // value不能省略
private String name;
@Test(300) // value可以省略
public void test1() {System.out.println("test1");}
public static void main(String[] args) throw Exception{
Class<TestAnnotation> classT = null;
classT = (Class<TestAnnotation>) Class.forName("com.annotation.TestAnnotation");
Method method = classT.getMethod("test1");
System.out.println(method);
//获取指定方法的所有注解
Annotation[] annotations = classT.getMethod("test1").getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation);
//将注解强转成所需要的注解类型
if (annotation instanceof Test) {
Test temp = (Test) annotation;
//通过注解对象的抽象方法来访问注解中的元数据
System.out.println("name :" + temp.name());
System.out.println("value :"+temp.value());
String[] names = temp.names();
for (String tempName : names) {
System.out.println("names :"+tempName);
}
}
}
}
小结
Class 、Constructor、 Method、 Field等程序元素均是AnnotatedElement接口的子类。当通过反射获取到某个程序元素以后,就可以通过其父接口AnnotatedElement提供的方法来获取该程序元素上的注解信息。
AnnotatedElement接口提供了如下几个方法帮助开发者获取注解信息
<T extends Annotation> T getAnnotation(Class<T> annotationClass);--返回程序元素上指定类型注解
default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
-- java8新增方法,返回直接修饰该程序元素,指定类型的注解
Annotation[] getAnnotations();-- 返回程序元素上所有的注解
Annotation[] getDeclaredAnnotations();-- 返回直接修饰该程序元素的所有注解
default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
--- java8新增方法,与重复注解有关,获取指定类型的多个注解
default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
--- java8新增方法,与重复注解有关,获取直接修饰该程序元素,指定类型的多个注解
default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
-- 判断该程序元素上是否存在指定类型的注解
示例代码 : 获取重复注解
public static void main(String[] args) throws ClassNotFoundException {
Class<People> clazz = (Class<People>) Class.forName("com.annotation.People");
// java 8 以前获取重复注解的方式
Roles roles = clazz.getDeclaredAnnotation(Roles.class);
Role[] rolesArray = roles.value();
for (Role role : rolesArray) {
System.out.println(role.value());
}
// java 8新增获取重复注解的方式
Role[] roleArray = clazz.getDeclaredAnnotationsByType(Role.class);
for (Role role : roleArray) {
System.out.println(role.value());
}
}