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",后加小括号。

时间: 2025-01-27 16:24:33

Java利用反射实现注解简单功能的相关文章

利用反射调用注解

利用反射调用注解 package net.jeesite.java; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.reflect.Method; @Retention(value = RetentionPolicy.RUNTIME) @interface Meta { String length(); String name(); int

Java利用反射访问对象的私有成员

当我们使用反射为java对象的全部字段逐一赋值的时候,私有字段是不允许直接访问的. 在java.lang.reflect当中,有几个比较实用的API可以解决: getDeclaredFields() :获得所有访问级别的字段 setAccessible(boolean flag): 修改类成员的可访问性 下面以一个JavaBean 对象 转 DBObject 对象的方法为例: public static DBObject bean2DbObject(DBObject dbObject, PicI

java利用反射机制判断对象的属性是否为空

java利用反射机制判断对象的属性是否为空: Map<String,String> validateMap = new LinkedHashMap<String, String>(); validateMap.put("serial", "编号");validateMap.put("major", "专业"); public static <T> String validateFiledIs

Java 自定义注解及利用反射读取注解

一.自定义注解 元注解: @interface注解: 定义注解接口 @Target注解: 用于约束被描述的注解的使用范围,当被描述的注解超出使用范围则编译失败.如:ElementType.METHOD,ElementType.TYPE: @Retention 注解:用于约束被定义注解的作用范围,作用范围有三个: 1,.RetentionPolicy.SOURCE:作用范围是源码,作用于Java文件中,当执行javac时去除该注解. 2.RetentionPolicy.CLASS:作用范围是二进制

java 通过反射和注解创建对象

|--要求 通过反射和注解的方式创建一个对象 |--代码 1 package com.annotation; 2 3 /** 4 * @auther::9527 5 * @Description: 元注解配合测试 6 * @program: jstl2 7 * @create: 2019-10-04 21:47 8 */ 9 public class Preson { 10 11 private String name; 12 private Integer age; 13 private St

java利用反射完成不同类之间相同属性的复制

如果我们有两个不同的类对象,但他们具有相同的属性,我们怎么将一个对象的属性值复制给另外一个对象呢? 我们可以利用反射完成这个需求:首先我们利用反射得到两个对象的所有属性,再通过循环得到源对象(被复制的对象)每个属性值,然后再将值复制给目标对象(复制的对象)的属性. 源对象的类: public class UserSource { private String name; private int age; private String address; public String getName(

Java利用反射排序

前言 Java为我们提供了几种排序得方法,比如Arrays和Collections类,但是前提是数组或者集合中的元素都必须实现Comparable接口,基本的数据类型都已经实现了Comparable接口了,所以我们才能够直接对基本类型的数组或者集合进行排序,比如Float和Integer类得源码. 今天记录一下对Comparable得使用和反射得使用. 先看一个Student类 我们要对他进行年龄排序,可以用冒泡进行排序,或者用选择排序法 但是这不是主角, 而我们要用Comparable接口进行

跟王老师学注解(五):利用反射读取注解信息

跟王老师学注解(五):读取注解信息 主讲教师:王少华   QQ群号:483773664 一.注解被读取 (一)条件 当一个注解类型被定义为运行时注解后,该注解才是运行时可以见,当class文件被装载时被保存在class文件中的注解才会被Java虚拟机所读取. 要把@Retention注解的value成员变量的值设为RetentionPolicy.RUNTIME (二)办法 我们已知所有的注解都是继承的java.lang.Annotation接口,也就是说Annotation是所有接口的父接口.除

java利用反射对pojo进行排序后转String

最近由于业务需求,在跟其他的系统进行通信时要求对pojo中的域进行排序,然后域的升序或降序再转化成String,即双方进行md5校验时按照相同的规则 根据需求利用发射写了个工具类,给大家分享出来,供大家参考 /**     * 按照给定类的域进行排序,然后用指定的分割符进行分割<br/>     * @param instance 需要操作的类的实例     * @param desc 如果true表示降序,如果是false按照升序     * @param separator 域之间的分隔符