廖雪峰Java4反射与泛型-2注解-3处理注解

java

1.处理注解

  • 注解本身对对代码逻辑没有任何影响
  • SOURCE类型的注解在编译期就被丢掉了
  • CLASS类型的注解仅保存在class文件中
  • RUNTIME类型的注解在运行期可以被读取
  • 如何使用注解由工具决定

因此如何处理注解只针对RUNTIME类型的注解
如何读取RUNTIME类型的注解
思路:

  • Annotation也是class
  • 所有Annotation继承自java.lang.annotation.Annotation
  • 使用反射API,就可以获取

2.使用反射API读取Annotation

Report.java

package com.reflection;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.TYPE)

@Retention(RetentionPolicy.RUNTIME)

public @interface Report {

int type() default 0;

String level() default "info";

String value() default "";

}

Person.java

package com.reflection;

@Report(type=1,level = "error")

public class Person {

}

  • 方法1: 判断某个Annotation是否存在,存在再打印注解的信息

    • Class.isAnnotationPresent(Class)
    • Field.isAnnotationPresent(Class)
    • Method.isAnnotationPresent(Class)
    • Constructor.isAnnotationPresent(Class)

package com.reflection;

public class Main {

public static void main(String[] args){

Class cls = Person.class;

if (cls.isAnnotationPresent(Report.class)){

Report report = (Report) cls.getAnnotation(Report.class);

int type = report.type();

String level = report.level();

System.out.println(type+"\t"+level);

}

}

}

  • 方法2:获取某个Annotation,注解对象不为空,再打印注解的信息

    * Class.getAnnotation(Class)

    * Field.getAnnotation(Class)

    * Method.getAnnotation(Class)

    * Constructor.getAnnotation(Class)

    * getParameterAnnotations()

package com.reflection;

public class Main {

public static void main(String[] args){

Class cls = Person.class;

Report report = (Report) cls.getAnnotation(Report.class);

if (report != null){

int type = report.type();

String level = report.level();

System.out.println(type+ "\t" + level);

}

}

}

3.读取方法参数的Annotation:

NotNull.java

package com.reflection;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.PARAMETER)

public @interface NotNull{

}

Range.java

package com.reflection;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)

@Retention(RetentionPolicy.RUNTIME)

public @interface Range{

int min() default 1;

int max() default 100;

}

Hello.java

package com.reflection;

import java.lang.annotation.Annotation;

import java.lang.reflect.Method;

public class Hello {

public String hello(@NotNull String name,@NotNull @Range(max = 5) int age){

return name+"\t"+age;

}

}

TestHello.java

import java.lang.annotation.Annotation;

import java.lang.reflect.Method;

import java.lang.reflect.Parameter;

public class TestHello {

public static void main(String[] args) throws Exception{

Class cls = Hello.class;

Method m = cls.getMethod("hello", String.class, int.class);

//方法的参数本身可以看作是一个数组,每一个参数又可以定义多个注解。因此一次获取所有方法的注解,要用2维数组来表示

Annotation[][] annos = m.getParameterAnnotations();

Parameter[] params = m.getParameters();

for(int i=0;i<annos.length;i++){

System.out.print(params[i]+"\t{");

for(Annotation anno:annos[i]){

System.out.print(anno.toString()+"\t");

}

System.out.print("}");

System.out.println();

}

}

}

4.读取字段的Annotation

NotNull.java

package com.reflection;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.FIELD)

public @interface NotNull{

}

Range.java

package com.reflection;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Range{

int min() default 1;

int max() default 100;

}

Person.java

package com.reflection;

public class Person{

@NotNull

public String name;

@Range(max=20)

public int age;

public Person(String name,int age){

this.name=name;

this.age = age;

}

}

Main.java

package com.reflection;

//Java注解本身对代码逻辑并不产生任何影响,所以应用的这些注解并不会自动对name和age进行检查,我们需要自己的代码应用这些注解

import java.lang.reflect.Field;

public class Main{

public static void main(String[] args) throws Exception{

Person p1 = new Person("xiaoming",25);

Person p2 = new Person(null,15);

checkPerson(p1);

checkPerson(p2);

}

static void checkPerson(Person p) throws Exception{

System.out.println("check " +p + "...");

Class cls = Person.class;

for(Field f:cls.getFields()){

checkField(f,p);

}

}

static void checkField(Field f,Person p) throws Exception{

if (f.isAnnotationPresent(NotNull.class)){

Object r = f.get(p);

if (r==null){

System.out.println("Error Field " + f.getName() + "is null...");

}

}

if (f.isAnnotationPresent(Range.class)){

Range range = f.getAnnotation(Range.class);

int n = (Integer) f.get(p);//参见反射2field

if(n < range.min() || n > range.max()){

System.out.println("Error Field " + f.getName()+ "is out of range...");

}

}

}

}

5.总结:

  • 可以在运行期通过反射读取RUNTIME类型的注解,不要漏写@Retention(RetentionPolicy.RUNTIME)
  • 可以通过工具处理注解来实现相应的功能

    * 对JavaBean的属性值按规则进行检查

    * JUnit会自动运行@Test注解的测试方法

请根据注解:

  • @NotNull检查该属性为非null
  • @Range检查整形介于minmax,或者检查字符串长度介于minmax
  • @ZipCode: 检查字符串是否全部由数字构成,且长度恰好为value

实现对Java Bean的属性值检查。如果检查为通过,抛出异常

以上是 廖雪峰Java4反射与泛型-2注解-3处理注解 的全部内容, 来源链接: utcz.com/z/391286.html

回到顶部