Java注解(Annotation)的基本知识
此文的目的只在于了解的注解的基本知识,知道注解的一些概念,使能够看懂注解的使用。
注解概述
- Java 注解(Annotation)又称 Java 标注,使 JDK5.0 引入的一种注释机制。
- Java 语言中的类、构造器、方法、成员变量、参数等都可以被注解进行标注。
注解的作用是什么呢?
- **对 Java 中类、方法、成员变量做标记,然后进行特殊处理,**至于到底作何种处理由业务需求来决定。
- 例如: JUnit框架中,标记了注解 @Test 的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法。
- 代码文档化: 注解可以用来为代码添加说明文档,例如
@Deprecated
标记已弃用的方法或类。 - 编译时检查: 通过自定义的注解,在编译时进行代码检查,例如检查代码规范、约定等。
- 运行时处理: 注解可以在运行时被读取并进行处理,例如自定义的业务逻辑、AOP(面向切面编程)等。
- 框架和库的使用: 许多 Java 框架和库使用注解来配置和控制程序的行为,比如 Spring 框架中的
@Autowired
、@RequestMapping
等。
自定义注解
自定义注解就是自己做一个注解来使用。
public @interface 注解名称 {public 属性类型 属性名() default 默认值; //其中属性类型 Java 支持的数据类型基本上都支持
}
定义案例:
public @interface TestAnnotation {public String myName() default "xwhking";public String sex() default "man";
}
特殊属性
- value 属性,如果只有一个 value 属性的情况下,使用 value 属性的时候可以省略 value 名称不写!!
- 但是如果有多个属性,且多个属性没有默认值,那么 value 名称是不能省略的。
理解一下,这里的 value 指的是在使用注解时的区别,如果注解里面只有一个属性,那么就不需要特别说明,给注解里面注入值,那么就自动注入到该属性了,如果有多个属性,就需要表明是哪一个属性的值。看下面的例子
因为定义了 TestAnnotation 注解,如果 TestAnnotation 里面只有一个属性,如果只有 myName 的话,那么就不需要写 myName="XXX"
了,直接输入字符串即可,而这里因为有两个属性需要写一下属性名,并且进行对应 value。
元注解
元注解:就是给注解的注解,让我们方便定义注解的注解
元注解有两个:
- @Target:约束自定义注解只能在那些地方使用
- @Retention:申明注解的生命周期
@Target
@Target 中可使用的值定义在Element枚举类中,常用值如下
- TYPE,类、接口
- FIELD,成员变量
- METHOD,成员方法
- PARAMETER,方法参数
- CONSTRUCTOR,构造器
- LOCAL_VARIABLE,局部变量
@Retention
@Retention 中可使用的值定义在 RetentionPolicy 枚举类中,常用值如下:
- SOURCE : 注解之作用在源码阶段,生成的字节码文件中不存在
- CLASS: 注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
- RUNTIME:注解作用在源码、字节码、运行阶段
注解解析
注解的解析
注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容。
与注解解析相关的接口
-
Annotation: 注解的顶级接口,注解都是Annotation类型的对象
-
AnnotatedElement:该接口定义了与注解解析相关的解析方法
方法 | 说明 |
---|---|
Annotation[] getDeclaredAnnotations() | 获得当前对象上使用的所有注解,返回注解数组。 |
T getDeclaredAnnotation(Class annotationClass) | 根据注解类型获得对应注解对象 |
boolean isAnnotationPresent(Class annotationClass) | 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false |
<T extends Annotation> T getAnnotation(Class<T> annotationClass) | 根据注解类型获得对应注解对象(包括继承关系中的注解) |
- 所有的类成分Class, Method , Field , Constructor,都实现了AnnotatedElement接口他们都拥有解析注解的能力
getAnnotation(Class<? extends Annotation> annotationClass)
方法与getDeclaredAnnotation(Class<T> annotationClass)
方法功能相似,但是getAnnotation
方法会检查继承链中的注解。如果指定类型的注解存在于继承层次结构中,它会返回该注解;否则,返回 null。
解析注解的技巧
注解在哪个成分上,我们就先拿哪个成分对象。
- 比如注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解
- 比如注解作用在类上,则要该类的Class对象,再来拿上面的注解
- 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解
注解使用实例
上了上面那么多,知道了基本知识,现在我们来做一个实例,加深我们对注解的理解。
- 定义一个注解用于检测用户权限
/*** 定义权限控制注解*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PermissionRequired {String checkRole() default "user";
}
- 制造一个使用场景
public class UserController {@PermissionRequiredpublic String getUserData(){return "{" +"username:xwhking" +"password:admin123" +"}";}
}
- 利用注解对权限校验
public class CheckAuth {public static boolean check(Method method,String userRole){Annotation annotation = method.getAnnotation(PermissionRequired.class);if(annotation != null){String requiredRole = ((PermissionRequired) annotation).checkRole();if(userRole.equals(requiredRole)){return true;}}return false;}public static void main(String[] args) throws NoSuchMethodException {if(check(UserController.class.getMethod("getUserData"),"admin")){System.out.println("校验通过");}else{System.out.println("校验不通过!");}}
}
通过运行 CheckAuth 的主程序按照上面的代码运行的话结果是:
因为上面那个方法用了注解,没有给具体的值所以默认值是 "user"
与给的 "admin"
不一致所以不通过。
如果把上面用到注解的地方改为 @PermissionRequired("admin")
再次运行代码就可以通过了。