Java利用反射实现注解简单功能

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java利用反射实现注解简单功能相关的知识,希望对你有一定的参考价值。

//自定义一个简单的注解
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD,ElementType.PARAMETER,ElementType.LOCAL_VARIABLE})
public @interface Dougest { String value() default ""; }
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.lang.annotation.Annotation;
//方法测试类
@Dougest("annotation Dougest at class ")
public class TestAnnotation {
    @Dougest("annotation Dougest at field")
    String a = "2";
    @Dougest
    int b = 10000000;
    
    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
        TestAnnotation testAnnotation = new TestAnnotation();
        testAnnotation.a = "123";
        System.out.println(getObjectFieldsValue(testAnnotation));//结果 ==> {a=123, b=10000000}
        System.out.println(getObjectFieldValueByFieldName(testAnnotation,"a"));//结果 ==> 123
        System.out.println(getFieldValueByAnnotation(Dougest.class, testAnnotation));//结果 ==> {a=123, b=10000000}
        Dougest d = (Dougest)TestAnnotation.class.getAnnotation(Dougest.class);//结果 ==> 
        System.out.println(d.value());//结果 ==> annotation Dougest at class 
    }
    
    /**
     * 获取指定对象指定注解下属性值
     * @param annotation
     * @param obj
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    public static Object getFieldValueByAnnotation(Class<? extends Annotation> annotation,Object obj) throws IllegalArgumentException, IllegalAccessException{
        if(obj == null)
            throw new RuntimeException("cannot getFieldValueByAnnotation for null Object");
        if(annotation == null)
            throw new RuntimeException("cannot getFieldValueByAnnotation for null annotation");
        Map<String,Object> map = new HashMap<String,Object>();
        Field[] fields = obj.getClass().getDeclaredFields();
        for(Field field : fields) {
            field.setAccessible(true);
            if(field.isAnnotationPresent(annotation)) {
                map.put(field.getName(),field.get(obj));
            }
        }
        return map;
    }
    
    /**
     * 获取对象属性值
     * @param obj
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    @SuppressWarnings("rawtypes")
    public static Map<String,Object> getObjectFieldsValue(Object obj) throws IllegalArgumentException, IllegalAccessException {
        if(obj == null)
            throw new RuntimeException("cannot getObjectFieldsValue for null Object");
        Map<String,Object> map = new HashMap<String,Object>();
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields) {
            field.setAccessible(true);
            map.put(field.getName(), field.get(obj));
        }
        return map;
    }
    /**
     * 获取对象属性名获取属性值
     * @param obj
     * @return
     * @throws IllegalArgumentException
     * @throws IllegalAccessException
     */
    @SuppressWarnings("rawtypes")
    public static Object getObjectFieldValueByFieldName(Object obj,String fieldName) throws IllegalArgumentException, IllegalAccessException {
        if(obj == null)
            throw new RuntimeException("cannot getObjectFieldValueByFieldName for null Object");
        if(fieldName == null || "".equals(fieldName.trim()))
            throw new RuntimeException("cannot getObjectFieldValueByFieldName for null fieldName");
        Class clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for(Field field : fields) {
            field.setAccessible(true);
            if(fieldName.equals(field.getName())) 
                return field.get(obj);
        }
        return null;
    }
}

什么是注解(what)

定义:

  注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

我的理解:

   吾生而有涯,其学也无涯,以有涯随无涯,殆①已!
  注: ①殆 :危险
 
作用(why):

编写文档:通过代码里标识的元数据生成文档。
代码分析:通过代码里标识的元数据对代码进行分析。
编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查

我的理解:解释代码
  
元注解:
技术分享
  @Target 中 ElementType ( ElementType     ==> 作用域范围):
    1.CONSTRUCTOR:        用于描述构造器
    2.FIELD:                         用于描述域
    3.LOCAL_VARIABLE:    用于描述局部变量
    4.METHOD:                    用于描述方法
    5.PACKAGE:                  用于描述包
    6.PARAMETER:             用于描述参数
    7.TYPE:                       用于描述类、接口(包括注解类型) 或enum声明
  ElementType 的取值可以不止有一个,如下原码:
 
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    /**
     * Declares whether the annotated dependency is required.
     * <p>Defaults to {@code true}.
     */
    boolean required() default true;
}
代码的生命周期对应 @Retention
    1   源码(人可以识别的字符)阶段  xx.java
     2  编译阶段  xx.class
     3  执行阶段(被jvm加载交给CPU运行阶段)byte[]
    注解
         SOURCE     对应源码阶段
         CLASS        对应编译阶段
         RUNTIME     随时,包含上面两个阶段
 
 
 
应用场景
1.编译检查        @SupperessWarnings
2.在框架中使用,一般都会声明为runtime
        根据Annotation不同利用反射机制读取出Annotation中的内容
        从而根据不同的内容实现不同的逻辑
3.根据Annotation生成帮助文档        @Document
4.能够帮助我们提高代码的识别度  @Override
 

自定义注解(详情见最上面代码):

  使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。

  定义注解格式:
  public @interface 注解名 {定义体}

  注解参数的可支持数据类型:

    1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
    2.String类型
    3.Class类型
    4.enum类型
    5.Annotation类型
    6.以上所有类型的数组

  Annotation类型里面的参数该怎么设定: 
  第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;   
  第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;  
  第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号。

 













以上是关于Java利用反射实现注解简单功能的主要内容,如果未能解决你的问题,请参考以下文章

Java注解教程:自定义注解示例,利用反射进行解析

java反射+注解实现Entity类与Dto类相互转换

计算机程序的思维逻辑 (84) - 反射

利用反射做一个简易 Spring IOC 容器,模仿其装配功能

java筑基.泛型,反射,注解-利用注解加反射练习

java简单使用反射和注解