HOME
HOME
文章目录
  1. 0x01 什么是注解
  2. 0x02 定义注解
    1. 元注解
  3. 0x03 处理注解
  4. 参考文档

java安全学习之注解

0x01 什么是注解

注解是在java中类、方法、参数前面的一种特殊的注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.itranswarp.learnjava;

import javax.annotation.PostConstruct;

public class Demo1 {

int n;

@PostConstruct
public void Demo1(){
System.out.println("after construct");
}

public Demo1(){
System.out.println("construct");
}

@Override
public String toString(){
return "this is demo1";
}

public static void main(String[] args) {
Demo1 d = new Demo1();
}
}

注解共分为三类:

  1. 编译器使用的注释,如@Override,检查该方法是否正确的实现了覆写
  2. 由工具处理.class文件中使用的注解,一般在底层库使用
  3. 程序运行中能够读取的注解,类似于自定义的注解,加载后存在于jvm中

0x02 定义注解

在java中使用@interface语法来定义注解,例如Override的定义:

1
2
3
4
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

Override注解不带任何配置参数。@TargetRetention表示的是元注解,能够修饰自定义注解的注解

元注解

@Target

表示定义的注解能够被用到哪些位置:

  1. 类或者接口:ElementType.TYPE
  2. 字段:ElementType.FIELD
  3. 方法:ElementType.METHOD
  4. 构造方法:ElementType.CONSTRUCTOR
  5. 方法参数:ElementType.PARAMETER

可以定义一个注解同时用于方法或者字段上面,如下所示:

1
2
3
@Target({ElementType.FIELD, ElementType.METHOD})  // 使用数据表示
public @interface Demo2 {
}

@Retention

定义了注解的生命周期:

  1. 仅编译器:RetentionPolicy.SOURCE
  2. 仅class文件:RetentionPolicy.CLASS
  3. 运行期:RetentionPolicy.RUNTIME

如果@Retention不存在,则默认为CLASS,故在自定义注解时,需要写明@Retention(RetentionPolicy.RUNTIME)

还有一些其他属性,可查阅相关文档,不再赘述。

注解参数

在定义注解的时候可以定义一些参数,并且能够赋予默认的值,具体如下,原理类似于接口的定义,定义无方法体的方法。

1
2
3
4
5
6
7
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Report {
int type() default 0;
String level() default "info";
String value() default "";
}

0x03 处理注解

注解对java代码的运行逻辑没有任何影响,我们编写的RUNTIME类型的注解才会在代码运行时产生影响。

所有的注解都继承于java.lang.annotation.Annotation,读取注解需要使用反射API。

判断是否存在注解的API:

1
2
3
4
Class.isAnnotationPresent(Class) //是否类定义了注解
Field.isAnnotationPresent(Class) // 是否字段定义了注解
Method.isAnnotationPresent(Class) // 是否方法定义了注解
Constructor.isAnnotationPresent(Class) // 是否构造方法定义了注解

例如,创建构造函数的注解

注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.itranswarp.learnjava;


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.CONSTRUCTOR)
@Retention(RetentionPolicy.RUNTIME)
public @interface Construct_Annotation {
String descp() default "no description";
}

注解使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Demo4 {

@Construct_Annotation
public Demo4(){
System.out.println("构造函数");
}

@MethodAnnotation
public void hello(){
System.out.println("hello method");
}

public static void main(String[] args) {
Demo4 demo4 = new Demo4();
Constructor[] constructors = demo4.getClass().getConstructors();
for (Constructor con: constructors){

if (con.isAnnotationPresent(Construct_Annotation.class)){
System.out.println("构造函数注解找到");
}
}
}
}

注解的验证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
static void check(Person person) throws IllegalArgumentException, ReflectiveOperationException {
for (Field field : person.getClass().getFields()) {
Range range = field.getAnnotation(Range.class);
if (range != null) {
Object value = field.get(person);

if (value instanceof String){
int value_length = ((String) value).length();
System.out.println("当前filed:"+ field.getName()+ "的长度是"+ ((String) value).length());
if (value_length < range.min() || value_length > range.max()){
throw new IllegalArgumentException("Invalid field: " + field.getName());
}
}
if (value instanceof Integer){
if ((int) value < range.min() || (int) value > range.min()){
throw new IllegalArgumentException("Invalid field: " + field.getName());
}
}


}
}
}

注解定义:

1
2
3
4
5
6
7
8
9
10
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Range {

int min() default 0;

int max() default 255;

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class Person {

@Range(min = 1, max = 20)
public String name;

@Range(max = 10)
public String city;

@Range(min = 1, max = 100)
public int age;

public Person(String name, String city, int age) {
this.name = name;
this.city = city;
this.age = age;
}

@Override
public String toString() {
return String.format("{Person: name=%s, city=%s, age=%d}", name, city, age);
}
}

参考文档

  1. https://www.liaoxuefeng.com/wiki/1252599548343744/1255945389098144
  2. https://blog.csdn.net/pan_junbiao/article/details/85249614