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处理注解的更多相关文章

  1. 廖雪峰Java4反射与泛型-2注解-2定义注解

    1.定义注解 使用@interface定义注解Annotation 注解的参数类似无参数方法 可以设定一个默认值(推荐) 把最常用的参数命名为value(推荐) 2.元注解 2.1Target使用方式 ...

  2. 廖雪峰Java4反射与泛型-2注解-1使用注解

    1.Annotation定义 注解是放在Java源码的类.方法.字段.参数前的一种标签.如下 package com.reflection; import org.apache.logging.log ...

  3. 廖雪峰Java4反射与泛型-3泛型-7泛型和反射

    1.部分反射API是泛型 1.1获取反射API的泛型 部分反射API是泛型,如Class<T>是泛型 //如果使用Class,不带泛型,出现compile warning编译警告 Clas ...

  4. 廖雪峰Java4反射与泛型-3范型-4擦拭法

    1.擦拭法是Java泛型的实现方式. 编译器把类型视为Object. * 泛型代码编译的时候,编译器实际上把所有的泛型类型T统一视为Object类型.换句话说,虚拟机对泛型一无所知,所有的工作都是编译 ...

  5. 廖雪峰Java4反射与泛型-3范型-6super通配符

    1.super通配符 1.1super通配符第一种用法 泛型的继承关系 Pair<Integer>不是Pair<Number>的子类,如 static void set(Pai ...

  6. 廖雪峰Java4反射与泛型-3范型-5extends通配符

    1.泛型的继承关系: Pair<Integer>不是Pair<Number>的子类 add()不接受Pair<Integer> Pair.java package ...

  7. 廖雪峰Java4反射与泛型-3范型-3编写泛型

    编写泛型类比普通的类要麻烦,而且很少编写泛型类. 1.编写一个泛型类: 按照某种类型(例如String)编写类 标记所有的特定类型例如String 把特定类型替换为T,并申明 Pair.java pa ...

  8. 廖雪峰Java4反射与泛型-1反射-2访问字段Field和3调用方法Method

    2.字段Field 2.1.通过Class实例获取字段field信息: getField(name): 获取某个public的field,包括父类 getDeclaredField(name): 获取 ...

  9. 廖雪峰Java4反射与泛型-1反射-1Class类

    1.Class类与反射定义 Class类本身是一种数据类型(Type),class/interface的数据类型是Class,JVM为每个加载的class创建了唯一的Class实例. Class实例包 ...

随机推荐

  1. python基础-函数基本特性和用法

    函数: 初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因变量,y是x的函数.自变量x的取值 ...

  2. nodeJs项目 相关命令

    npm install -g cnpm --registry=https://registry.npm.taobao.org npm run dev

  3. UVA1455 【Kingdom】

    分析 直线都是\(y=\overline{a.5}\)这种形式,而只查询州和城市的个数,所以很容易想到对\(y\)轴做投影,然后转化为区间修改(加减)和单点查询,可以用线段树维护.至于每个州只会合并不 ...

  4. scala函数等号省略

    例1: 此时没有写返回值,但是有等号,函数会自己推断返回值,此时的返回值是Int def add(x:Int, y:Int) = { x+y} 例2: 此时没有写返回值,也没有等号,无论函数内部有没有 ...

  5. day 61 pymysql

    Python3连接MySQL 本文介绍Python3连接MySQL的第三方库--PyMySQL的基本使用. PyMySQL介绍 PyMySQL 是在 Python3.x 版本中用于连接 MySQL 服 ...

  6. openresty 集成 keycloak-oauth-oidc

    keycloak 是一个比较全,而且比较方便的sso 解决方案,同时为我们提供了灵活的扩展特性 备注: 测试使用docker-compose 运行,对于keycloak 使用pg 数据库做为后端存储 ...

  7. Python __name__变量

    原文: http://blog.csdn.net/u011511601/article/details/53504355 Python使用缩进对齐组织代码的执行,所有没有缩进的代码,都会在载入时自动执 ...

  8. chrome浏览器好用的插件

    1.Chrome批量保存所有选项卡网址 + 批量打开复制网址小插件 批量保存所有选项卡网址插件:Copy All Urls 经常搜索一些东西,下班时无法处理完所有网页内容,比如做笔记什么的,又不舍得关 ...

  9. jmeter—PerfMon Metrics Collector(附java.io.IOException: Agent is unreachable via TCP错误解决办法)

    jmeter—PerfMon Metrics Collector(附java.io.IOException: Agent is unreachable via TCP错误解决办法 转自https:// ...

  10. golang 自定义json解析

    在实际开发中,经常会遇到需要定制json编解码的情况. 比如,按照指定的格式输出json字符串, 又比如,根据条件决定是否在最后的json字符串中显示或者不显示某些字段. 如果希望自己定义对象的编码和 ...