使用注解
注解的定义
注解是写在类、方法、属性上的一种注释。区别于注释,注释不会被JVM编译到
class文件中,而注解会被带入,是一种用做标记的”元数据”。
注解用于对代码额外添加描述信息,这些信息被编译器,开发工具或运行时环境读取和处理,不会影响代码原本逻辑。
注解的作用
注解区分为三类:
- 类似与
@Override、@SuppressWarnings注解用于编译环节给编译器使用,校验方法是实现的和忽略警告。编译后不回带入到class文件中。 - 由工具处理
.class文件使用的注解,比如有些工具会在加载class的时候,对class做动态修改,实现一些特殊的功能。这类注解会被编译进入.class文件,但加载结束后并不会存在于内存中。这类注解只被一些底层库使用,一般我们不必自己处理。 - 程序运行期能够读取的注解,它们在加载后一直存在于
JVM中,这也是最常用的注解。例如,一个配置了@PostConstruct的方法会在调用构造方法后自动被调用(这是Java代码读取该注解实现的功能,JVM并不会识别该注解)。
注解的使用
注解可以用用在类、方法、属性上,注解一般都会存在参数,参数类型为:
- 所有的基本类型;
- String;
- 枚举类型;
- 基本类型、Class以及枚举数组。
注解一般都会有默认的属性
value,且属性都是常量的。 - 注解属性可能存在默认值,如果不填写属性则取默认值;
- 注解属性为常量,所以在使用时就需要给参数赋值。
代码实例
public class AnnotationDemo {
@NotNull //不能为空注解
private String name;
@Check(99) //value赋值为99
private int age;
}自定义注解
Java 语言使用 @interface 关键字来自定义注解,格式如下:
public @interface CustomizationAnnotationDemo {
String value() default "0";
}注解的参数一般用 value 表示,且推荐给参数加默认值。
元注解
注解的定义需要结合 JAVA 自带的一些注解,这些注解称为元注解。
@Target
用于标注注解的作用域,注解的参数可以设置可标注自定义注解用于 类或接口、方法、属性、方法参数。
- 类或接口:
ElementType.TYPE - 方法:
ElementType.METHOD - 属性:
ElementType.FIELD - 构造方法:
ElementType.CONSTRUCTOR - 方法参数:
ElementType.PARAMETER
参数类型是 ElementType[] 可以传入多个作用域,若只有一个作用范围可忽略数组写法。
@Target({ElementType.TYPE, ElementType.METHOD}) 或 @Target(ElementType.TYPE)。
@Retention
此注解作用为设置自定义注解的生命周期。
- 仅编译期:
RetentionPolicy.SOURCE - 仅class文件:
RetentionPolicy.CLASS - 运行期:
RetentionPolicy.RUNTIME
该注解只能传入一个参数,当不传入参数时默认作用范围为class文件。
@Repeatable
设置自定义注解是否可重复使用。
@Report(type=1, level="debug")
@Report(type=2, level="warning")
public class Hello {
}补充: 改注解的参数需要为当前自定义注解再设置一个容器注解,示例:
// 声明被重复注解的容器注解(必须)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Filters {
CustomizationAnnotationDemo[] value(); // 必须定义 value() 方法,返回被重复注解的数组
}
@Repeatable(Filters.class)
public @interface CustomizationAnnotationDemo {
String value() default "0";
}@Inherited
设置自定义注解注释后的类其子类自动添加该注解。且必须为子类实现类不行。
@Inherited
@Target(ElementType.TYPE)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}在使用自定义注解后:
@Report(type=1)
public class Person {
}其子类也拥有改注解的能力:
public class Student extends Person {
}如何自定义注解
- 先使用
@interface关键字自定义注解,并且设计注解参数给定默认值。 - 用以上元注解设置作用范围及生命周期等。
@Target({ElementType.TYPE, ElementType.METHOD,ElementType.FIELD,ElementType.CONSTRUCTOR,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface CustomizationAnnotationDemo {
String value() default "0";
}处理注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Range {
int min() default 0;
int max() default 255;
}
@Data
public class UserDemo {
@Range(min = 0,max = 20)
public String name;
@Range(min = 1,max = 3)
public int age;
public String sex;
}
//处理注解限制字段长度。
public class AnnotationDemo {
public static void main(String[] args) throws IllegalAccessException {
UserDemo userDemo = new UserDemo("张三", 181, "男");
AnnotationDemo annotationDemo = new AnnotationDemo();
annotationDemo.check(userDemo);
}
public void check(UserDemo userDemo) throws IllegalAccessException {
Field[] fields = userDemo.getClass().getFields();
for (Field field : fields) {
Range range = field.getAnnotation(Range.class);
if (range != null) {
int min = range.min();
int max = range.max();
Object object = field.get(userDemo);
try {
if (object instanceof String){
if (((String) object).length() < min || ((String) object).length() > max) {
throw new RuntimeException("字段" + field.getName() + "长度超出范围");
}
}
if (object instanceof Integer){
int value = (int) field.get(userDemo);
if (value < min || value > max) {
throw new RuntimeException("字段" + field.getName() + "大小超出范围");
}
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}