一:注解的作用
注解是jdk5引入的新特性,注解相当于增加了一个配置,当我们使用注解时,我们可以通过反射获取注解从而获取相关的配置,方便我们在代码层面做一些操作。
二:注解的相关概念以及使用
注解的分类:
- 供javadoc生成文档用的注解。@param @return 等。
- 自定义注解,相当于配置文件的作用,使用灵活,配置简单。
- 在编译时进行格式检查。@override检查是否重写了父类方法。@SuppressWarnings抑制编译器产生的警告信息。@Deprecated标记过时的方法等不推荐再使用。
包 java.lang.annotation 中包含所有定义自定义注解所需用到的元注解和接口。所有注解默认继承了java.lang.annotation.Annotation接口。
注解中概念:
自定义注解时使用了四个元注解,就是用于注解的注解。四个元注解分别是:@Target,@Retention,@Documented,@Inherited。
@Target定义注解作用的地方。可以是类、方法、属性等。常用的值由一个枚举类定义:ElementType。
ElementType.FIELD,//作用在属性上 ElementType.METHOD,//作用在方法上 ElementType.CONSTRUCTOR,//作用在构造函数上 ElementType.LOCAL_VARIABLE,//作用在本地变量上 ElementType.PACKAGE,//作用在包上 ElementType.PARAMETER,//作用在方法参数上 ElementType.TYPE//作用在类,接口,枚举类等
@Retention定义了注解的生命周期,即注解在什么范围内有效。
- SOURCE:在源文件中有效
- CLASS:在class文件中有效
- RUNTIME:在运行时有效(即运行时保留,我们自定义的注解一般是要在运行时使用的)
@Documented 表示此注解作用的内容会被javadoc工具提取到文档中。
@Inherited表示该注解会被继承。使用该元注解的自定义注解一般作用范围是ElementType.TYPE,如果是作用在ElementType.METHOD的注解,在子类重写了使用注解的方法的时候,此时子类重载方法是没有继承该注解的,不重写方法则子类可以获取继承的注解。
自定义注解的方式:
使用@interface来定义一个自定义注解,使用方法定义自定义注解中的属性,方法的返回值定义属性值的类型。
注解使用案例一:
注解定义:
@Target({ElementType.FIELD,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface DatasourceAnnotation { String datasourceName(); int sequence(); }
注解使用:
public class UserService { @DatasourceAnnotation(datasourceName = "master", sequence = 1) public String datasourceName; @DatasourceAnnotation(datasourceName = "salve", sequence = 2) public String selectUserNameById(Integer id) { return "test"; } }
public class AnnotationTest { private void handleFieldAnnotation() throws NoSuchFieldException { Field datasourceName = UserService.class.getField("datasourceName");//获取属性 if (datasourceName.isAnnotationPresent(DatasourceAnnotation.class)) {//判断属性上有无此注解 DatasourceAnnotation annotation = datasourceName.getAnnotation(DatasourceAnnotation.class);//获取注解 System.out.println(annotation.datasourceName()); System.out.println(annotation.sequence()); } } private void handleMethodAnnotation() throws NoSuchMethodException { Method selectUserNameById = UserService.class.getMethod("selectUserNameById", Integer.class); if (selectUserNameById.isAnnotationPresent(DatasourceAnnotation.class)) { DatasourceAnnotation annotation = selectUserNameById.getAnnotation(DatasourceAnnotation.class); System.out.println(annotation.datasourceName()); System.out.println(annotation.sequence()); } } @Test public void test() throws Exception { handleFieldAnnotation(); handleMethodAnnotation(); } }
运行结果:
master 1 salve 2 Process finished with exit code 0
注解使用案例二:继承注解(作用在ElementType.METHOD上 子类的重写方法是无法继承注解的,不重写方法子类是可以获取注解的)
注解定义:
@Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @Inherited public @interface InheritedAnnotation { String name(); }
注解使用:
@InheritedAnnotation(name = "test") public class UseInheritedAnnotation { }
public class SubUseInheritedAnnotation extends UseInheritedAnnotation{ }
@Test public void test() throws Exception { InheritedAnnotation annotation = SubUseInheritedAnnotation.class.getAnnotation(InheritedAnnotation.class); System.out.println(annotation.name()); }
运行结果:
test
Process finished with exit code 0
作用在ElementType.METHOD上 子类的重写方法是无法继承注解的,不重写方法子类是可以获取注解的
public class UseInheritedAnnotation { @InheritedAnnotation(name = "methodTest") public String test(){ return ""; } }
public class SubUseInheritedAnnotation extends UseInheritedAnnotation{ @Override public String test(){ return ""; } }
@Test public void test() throws Exception { Method test = SubUseInheritedAnnotation.class.getMethod("test", null); InheritedAnnotation annotation = test.getAnnotation(InheritedAnnotation.class); System.out.println(annotation.name()); }
运行结果:
java.lang.NullPointerException
at com.ctj.annotationTest.AnnotationTest.test(AnnotationTest.java:35)