目录
1、简述
注解(Annotation)是JDK5.0中引入的新特性。那么什么是注解呢?官方解释是:注解是一系列元数据,用于解释程序代码,可修饰类、方法、变量等,对修饰的代码没有直接影响。用比较通俗的话语来说,注解就是代码中的特殊标记,用于修饰代码(类,方法,变量等),并且对代码的运行效果没有直接影响。那么注解修饰代码有什么作用呢? 首先,注解可以提供信息给开发工具(编译器)用于检测错误或警告信息等;其次,在编译期,开发工具可以通过注解信息生成html文档或者做其他处理;最后,在运行前,可以利用反射机制获取注解的内容。当然这几个时期可以通过元注解设置,如果注解设置为源码期,则编译和运行时期就不会有注解信息,同理注解使用时期设置的是编译期的,则在运行期就获取不到注解信息。注解在平时后台开发,框架和jdk源码中都比较常见的,理解了注解,在后续的开发或学习源码时是特别有用的。
2、元注解
理解了注解概念,那么什么是元注解呢?通俗的说就是修饰注解的注解就叫做元注解,Java中的元注解有以下几个,分别为@Target,@Retention,@Documente,@Inherited,@Repeatable(JDK1.8引入的)。下面介绍下这几个元注解:
@Target
描述了注解应该用于什么地方,即使用范围。取值在java.lang.annotation.ElementType 枚举类中,分别为:
- TYPE:类,接口(包括注释类型)或枚举声明
- FIELD:字段声明(包括枚举常数)
- METHOD:方法声明
- PARAMETER:正式参数声明
- CONSTRUCTOR:构造函数声明
- LOCAL_VARIABLE:局部变量声明
- ANNOTATION_TYPE:注解类型声明
- PACKAGE:包声明
// 表示此注解可以修饰类,接口,方法,构造方法,不能修饰其他
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR})
@interface MyAnnotationOne {
}
// 表示此注解只能用于方法,不能修饰其他
@Target({ElementType.METHOD})
@interface MyAnnotationTwo {
}
@MyAnnotationOne
class Person {
@MyAnnotationTwo
public void fun() { }
}
@Retention
描述了被修饰注解使用的生命周期,注解的只取RetentionPolicy枚举类,值如下:
- SOURCE:表示注解只存在于源码时期,编译的class文件中就没有此注解了。
- CLASS:表示注解存在于编译期。
- RUNTIME:表示注解存在于运行期,在运行期还可通过反射机制获取注解的值。
@Retention(value=RetentionPolicy.SOURCE)
@interface MyAnnotationOne {
}
// 此处value= 可以省略
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotationTwo {
}
@Documented
这个注解说明了被修饰的注解可以被文档化,这是一个标记注解,标记注解就是没有成员的注解。
@Inherited
这个注解也是个标记注解,字面意思是继承的意思,它说的是如果某个类A(非接口)被@Inherited注解修饰的注解B所修饰,则类A的子类自动继承了注解B。
@Repeatable
这个注解是在JDK1.8引入的,是重复的意思。怎么用呢?例如,在一个管理系统中,角色可能有管理员,教师,指导员,导师,学生等,某个人可能有其中几个角色,我们需要通过注解的方式来实现,那么此时就可以用@Repeatable注解,示例如下:
public class RepeatableTest {
public static void main(String[] args) {
Class<User> manClass = User.class;
boolean flag = manClass.isAnnotationPresent(UserRoles.class);
if (flag) {
UserRoles userRoles = (UserRoles) manClass.getAnnotation(UserRoles.class);
for (Role role : userRoles.value()) {
System.out.println(role.roleName());
}
}
}
}
@Repeatable(UserRoles.class)
@interface Role {
String roleName() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface UserRoles {
Role[] value();
}
@Role(roleName="admin")
@Role(roleName="tutor")
class User { }
3、常用注解
Java还提供了几个常用的注解,有@Override,@Deprecated,@SuppressWarnings等等。
- @Override:指的是重写,基本上在子类重写父类方法时会使用,子类方法用了此注解,但方法名和父类不同时,IDE工具基本都会做错误提示的。
- @Deprecated:指的是废弃,一般JDK源码中非常常见,例如某个方法过时了,此时会用此注解,提示开发者,此方法过时了,不要再用了(实际上还可以用,但建议不要使用过时的方法)。
- @SuppressWarnings:指的是忽视警告,例如使用了废弃的方法,实现了Serializable但未生成serialVersionUID,IDE工具都会做提示,此时使用此注解可以忽略警告。
4、自定义注解
有时候我们需要使用注解,但现有的注解又无法满足要求,则可以自定义注解。自定义注解有以下几个规则:
- 自定义注解格式为:修饰符 @interface 注解名 { 注解体 },注解体的格式为:修饰符 类型 成员名() default 成员默认值;
- 注解可以没有注解体,此时注解为标记注解,只起标记作用;成员可以没有默认值。
- 注解和成员的修饰符只能为public或默认访问权限。
- 成员类型只能为基本数据类型、数组、String、枚举,类等数据类型,不能为自定义数据类型。
- 获取注解信息需要通过反射机制获取。
5、示例
下面通过一个简单的示例来学习下自定义注解(示例中用到了反射,不了解反射机制的先看下:https://blog.csdn.net/lanmuhhh2015/article/details/102462338):
package com.base.annotation;
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;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class CustomAnnotation {
public static void main(String[] args) throws Exception {
Class<?> userClass = Class.forName("com.base.annotation.User");
// 获取类的相关注解值
getClassAnnotationVal(userClass);
// 获取类中方法的相关注解值
getMethodAnnotationVal(userClass);
// 获取类中属性的相关注解值
getFieldAnnotationVal(userClass);
}
private static void getClassAnnotationVal(Class<?> obj) {
String className = obj.getName();
// 获取类的AuthorAnnotation注解值
boolean isHaveAnn = obj.isAnnotationPresent(AuthorAnnotation.class);
if (isHaveAnn) {
AuthorAnnotation author = obj.getAnnotation(AuthorAnnotation.class);
System.out.println(className + ":" + author.name());
}
// 获取类的DescriptionAnnotation注解值
isHaveAnn = obj.isAnnotationPresent(DescriptionAnnotation.class);
if (isHaveAnn) {
DescriptionAnnotation des = obj.getAnnotation(DescriptionAnnotation.class);
System.out.println(className + ":" + des.value());
}
}
private static void getMethodAnnotationVal(Class<?> obj) {
Method[] methods = obj.getDeclaredMethods();
boolean flag = false;
for (Method method : methods) {
String methodName = method.getName();
flag = method.isAnnotationPresent(AuthorAnnotation.class);
if (flag) {
AuthorAnnotation ann = method.getAnnotation(AuthorAnnotation.class);
System.out.println(methodName+":"+ann.name());
}
flag = method.isAnnotationPresent(DescriptionAnnotation.class);
if (flag) {
DescriptionAnnotation des = method.getAnnotation(DescriptionAnnotation.class);
System.out.println(methodName+":"+des.value());
}
}
}
private static void getFieldAnnotationVal(Class<?> obj) {
Field[] fields = obj.getDeclaredFields();
boolean flag = false;
for (Field field : fields) {
String fieldName = field.getName();
flag = field.isAnnotationPresent(AuthorAnnotation.class);
if (flag) {
AuthorAnnotation ann = field.getAnnotation(AuthorAnnotation.class);
System.out.println(fieldName+":"+ann.name());
}
flag = field.isAnnotationPresent(DescriptionAnnotation.class);
if (flag) {
DescriptionAnnotation des = field.getAnnotation(DescriptionAnnotation.class);
System.out.println(fieldName+":"+des.value());
}
}
}
}
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface AuthorAnnotation {
String name() default "zhangsan";
}
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface DescriptionAnnotation {
String value();
}
@AuthorAnnotation
@DescriptionAnnotation("this is a user class")
class User {
@DescriptionAnnotation("this is userName field")
private String userName;
@AuthorAnnotation(name="lisi")
@DescriptionAnnotation("this is getUserName function")
public String getUserName() {
return userName;
}
@AuthorAnnotation(name="wangwu")
@DescriptionAnnotation(value="this is setUserName function")
public void setUserName(String userName) {
this.userName = userName;
}
}
运行结果:
com.base.annotation.User:zhangsan
com.base.annotation.User:this is a user class
getUserName:lisi
getUserName:this is getUserName function
setUserName:wangwu
setUserName:this is setUserName function
userName:this is userName field