从JDK1.5开始,引入了源代码中的注解机制。鉴于目前大部分框架(Spring)都使用了注解简化代码并提高编码的效率,因此掌握并深入理解注解对于一个java工程师来说是很有必要的事。
元数据
描述数据的数据
1. 注解和注释的区别
注释 | 注解 |
---|---|
提供代码功能的说明(描述作用) | 实现程序功能的重要组成部分 |
不会被程序所读取 | 可以在编译、类加载、运行时被读取,并执行相应处理 |
2. 注解分类
2.1 内建注解(基本注解)
在java.lang包中,都继承自java.lang.annotation.Annotation
注解 | 描述 | 作用 |
---|---|---|
@Override | 限定重写父类方法 | 方法 |
@Deprecated | 标记已过时 | 方法、包、属性、构造方法、局部变量、参数、类 |
@SuppressWarnings | 抑制编译器警告(消除警告信息)诸如使用泛型类提示 | 方法、属性、构造方法、局部变量、参数、类 |
@SuppressWarnings注解的参数
参数 | 作用 |
---|---|
deprecation | 使用了过时的程序元素 |
unchecked | 执行了未检查的转换 |
unused | 有程序元素未被使用 |
fallthrough | switch程序块直接通往下一种情况而没有break |
path | 在类路径中有不存在的路径 |
serial | 在可序列化的类上缺少serialVersionUID定义 |
finally | 任何finally子句都不能正常完成 |
all | 所有情况 |
比如:
2.2 元注解
java为注解提供了4种注解。也就是说:
- 注解:对类、方法、接口进行注解
- 元注解:对注解进行注解
注解 | 描述 |
---|---|
@Target | 用于指定被修饰的注解能用于修饰哪些程序元素 |
@Retention | 用于指定被修饰的注解可以保留多长时间 |
@Documented | 使用了此注解的彼注解,在彼注解修饰的程序的API文档中将包含彼注解说明 |
@Inherited | 默认情况下,父类的注解不被子类继承,如果想要继承父类注解,就必须使用此注解 |
-
@Target
该注解具有value属性,被该注解修饰的注解只能用来注解对应的目标。
属性值 描述 ElementType.ANNOTATION_TYPE 注解类型声明 ElementType.CONSTRUCTOR 构造方法声明 ElementType.FIELD 字段声明(包括枚举常量) ElementType.LOCAL_VARIABLE 局部变量声明 ElementType.METHOD 方法声明 ElementType.PACKAGE 包声明 ElementType.PARAMETER 参数声明 ElementType.TYPE 类、接口(包括注解类型)或枚举声明
-
@Retention
如果注解定义中不存在此元注解,则保留策略默认为RetentionPolicy.CLASS
此注解包含一个RetentionPolicy类型的value属性,使用此注解必须指定value值
属性值 描述 RetentionPolicy.CLASS 编译器将把注解记录在class文件中,当运行java程序时,虚拟机不再保留注解 RetentionPolicy.RUNTIME 编译器将把注解记录在class文件中,当运行java程序时,虚拟机八六注解,程序可以通过反射获取该注解 RetentionPolicy.SOURCE 编译器将直接丢弃被修饰的注解
2.3 自定义注解
自定义注解想起作用,必须使用元注解修饰。
2.3.1 注解语法
@Target(ElementType.METHOD)
@interface MyAnnotation
自定义注解可以定义属性,以无参方法的形式声明,如:
@Target(ElementType.METHOD)
@interface MyAnnotation{
//定义一个属性value
String value();
}
可以按如下格式使用MyAnnotation注解:
public class Test{
//如果没有写属性名,而这个注解又有value值,则将这个值赋给value属性
//@MyAnnotation("good")
@MyAnnotation(value="good")
public void getObjectInfo(){
}
}
可以修改自定义注解MyAnnotation包含两个属性,并赋默认值,如:
@Target(ElementType.METHOD)
@interface MyAnnotation{
//定义两个属性name和age
String name() default "张三";
int age() default 22;
}
使用注解:
public class Test{
//使用带属性的注解时,需要为属性赋值
@MyAnnotation(name="李四",age=18)
public void getObjectInfo(){
}
}
使用带属性的注解时,需要给属性赋值。如果自定义注解给属性赋了默认值,则可使用不带属性值的注解,让注解使用自己的默认值。
2.3.2 注解使用形式
- 不带参数:@Annotation,例如@Override
- 带一个参数:@Annotation(参数),如@SuppressWarnings(value=“unused”)
- 带多个参数:@Annotation({参数1,参数2,参数3…}),如@MyAnno(name=“xxx”,age=15)
2.3.3 记录一次自定义注解的使用----验证信息
使用场景:通过注解来进行验证和部署
package annotation;
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.InvocationTargetException;
import java.lang.reflect.Method;
/**
*@author:秦淏
*@version:2020年12月11日
*@TODO:
*/
public class TestAnno {
/*
* 三个成员属性
*/
@MyAnno
private Integer id;
private String name;
private String path;
/*
* 提供getter/setter 方法
*/
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
/*
* 提供构造方法
*/
public TestAnno() {
super();
// TODO Auto-generated constructor stub
}
public TestAnno(Integer id, String name, String path) {
super();
this.id = id;
this.name = name;
this.path = path;
}
@Override
@Deprecated
@SuppressWarnings(value = { "unchecked","unused" })
public String toString() {
// TODO Auto-generated method stub
return super.toString();
}
/*
* 验证数据完整性
*/
public static void main(String[] args) {
//通过反射获取TestAnno类的所有属性
Class<TestAnno> test = TestAnno.class;
Field[] field = test.getDeclaredFields();
//遍历所有属性
for (int i = 0; i < field.length; i++) {
//判断属性是否使用了MyAnno自定义注解
if(field[i].getAnnotation(MyAnno.class)!=null) {
//使用了注解即可继续下一个属性
continue;
}
/*
* 没有使用MyAnno自定义注解的,判断是否存在对应的get方法
*/
String fie = field[i].getName().substring(0, 1).toUpperCase()+field[i].getName().substring(1);
try {
Method method = test.getMethod("get"+fie);
if(method.invoke(test) == null) {
System.out.println("数据不完整");
}
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
/*
* 定义一个注解,只能使用在属性上,可以通过反射获取该注解
*/
@Target(ElementType.FIELD)
@interface MyAnno{}