Java Annontation 注解的学习和理解

Posted OneIsAll

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java Annontation 注解的学习和理解相关的知识,希望对你有一定的参考价值。

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

/**
Annontation是Java5开始引入的新特征,中文名称叫注解。
它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。
为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。
Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
 
Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。
注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。
包含在 java.lang.annotation 包中。

常见的用法 :
      1、生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等
      2、跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2依赖注入,未来java开发,将大量注解配置,具有很大用处;
      3、在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。
      
注解的原理:
    注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。
    而我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象$Proxy1。
    通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。
    该方法会从memberValues这个Map中索引出对应的值。
    而memberValues的来源是Java常量池。

元注解:
   @Documented –注解是否将包含在JavaDoc中
   @Retention –什么时候使用该注解
   @Target –注解用于什么地方
   @Inherited – 是否允许子类继承该注解
   
1.)@Retention– 定义该注解的生命周期
  ●   RetentionPolicy.SOURCE : 在编译阶段丢弃。
           这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。
        @Override, @SuppressWarnings都属于这类注解。
        
  ●   RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
  
  ●   RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

2.)@Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType参数包括
  ● ElementType.CONSTRUCTOR:用于描述构造器
  ● ElementType.FIELD:成员变量、对象、属性(包括enum实例)
  ● ElementType.LOCAL_VARIABLE:用于描述局部变量
  ● ElementType.METHOD:用于描述方法
  ● ElementType.PACKAGE:用于描述包
  ● ElementType.PARAMETER:用于描述参数
  ● ElementType.TYPE:用于描述类、接口(包括注解类型) 或enum声明

3.)@Documented–一个简单的Annotations标记注解,表示是否将注解信息添加在java文档中。

4.)@Inherited – 定义该注释和子类的关系
        @Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。
         如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
*/
public class AnnoDefined {

}

 

 

 

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created on 19941115</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

public class AnnoDemo {
    
    @FieldMeta(id=true,name="序列号",order=1,description="ID")  
    private int id;  
    
    @FieldMeta(name="姓名",order=3,description="姓名")  
    private String name;  
    
    @FieldMeta(name="年龄",order=2)  
    private int age;  
    
    @FieldMeta(description="描述",order=4)  
    public String desc(){  
        return "java反射获取annotation的测试";  
    }  
    
    public int getId() {  
        return id;  
    }  
    public void setId(int id) {  
        this.id = id;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
    public int getAge() {  
        return age;  
    }  
    public void setAge(int age) {  
        this.age = age;  
    }  

}

 

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

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

/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:FieldMeta   
* @Description:   <p> @FieldMeta  - 注解描述信息 </p>
* @Author: - Jason   
* @CreatTime:2018年10月18日 下午9:53:45   
* @Modify By:   
* @ModifyTime:  2018年10月18日
* @Modify marker:   
* @version    V1.0
 */
@Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到  
@Target({ElementType.FIELD,ElementType.METHOD})//定义注解的作用目标**作用范围字段、枚举的常量/方法  
@Documented//说明该注解将被包含在javadoc中  
public @interface FieldMeta {
    
    /** 
     * 是否为序列号 
     * @return 
     */  
    boolean id() default false; 
    
    /** 
     * 字段名称 
     * @return 
     */  
    String name() default "default_name";  
    
    /** 
     * 是否可编辑 
     * @return 
     */  
    boolean editable() default true;  
    
    /** 
     * 是否在列表中显示 
     * @return 
     */  
    boolean summary() default true;  
    
    /** 
     * 字段描述 
     * @return 
     */  
    String description() default ""; 
    
    /** 
     * 排序字段 
     * @return 
     */  
    int order() default 0;  

}
/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created on 19941115</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

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

/*1.CONSTRUCTOR:用于描述构造器
2.FIELD:用于描述域
3.LOCAL_VARIABLE:用于描述局部变量
4.METHOD:用于描述方法
5.PACKAGE:用于描述包
6.PARAMETER:用于描述参数
7.TYPE:用于描述类、接口(包括注解类型) 或enum声明*/

/*(RetentionPoicy)
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)*/

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
    
    String value() default "Apple";
}
/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;


/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:Parent   
* @Description:   <p> Parent<T> </p>
* @Author: - Jason   
* @CreatTime:2018年10月18日 下午9:54:26   
* @Modify By:   
* @ModifyTime:  2018年10月18日
* @Modify marker:   
* @version    V1.0
 */
public class Parent<T> {
    
    private Class<T> entity;  
      
    public Parent() {  
        init();  
    }  
  
    public List<SortableField> init(){  
        List<SortableField> list = new ArrayList<SortableField>();  
        /**getClass().getGenericSuperclass()返回表示此 Class 所表示的实体(类、接口、基本类型或 void) 
         * 的直接超类的 Type(Class<T>泛型中的类型),然后将其转换ParameterizedType。。 
         *  getActualTypeArguments()返回表示此类型实际类型参数的 Type 对象的数组。 
         *  [0]就是这个数组中第一个了。。 
         *  简而言之就是获得超类的泛型参数的实际类型。。*/  
       // entity = (Class<T>)((ParameterizedType)this.getClass().getGenericSuperclass()).getActualTypeArguments()[0];  
//      FieldMeta filed = entity.getAnnotation(FieldMeta.class);  
        this.getClass().getGenericSuperclass();
        //genericSuperclass.
        if(this.entity!=null){  
              
            /**返回类中所有字段,包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段 
             * entity.getFields();只返回对象所表示的类或接口的所有可访问公共字段 
             * 在class中getDeclared**()方法返回的都是所有访问权限的字段、方法等; 
             * 可看API 
             * */  
            Field[] fields = entity.getDeclaredFields();  
//            
            for(Field f : fields){  
                //获取字段中包含fieldMeta的注解  
                FieldMeta meta = f.getAnnotation(FieldMeta.class);  
                if(meta!=null){  
                    SortableField sf = new SortableField(meta, f);  
                    list.add(sf);  
                }  
            }  
              
            //返回对象所表示的类或接口的所有可访问公共方法  
            Method[] methods = entity.getMethods();  
              
            for(Method m:methods){  
                FieldMeta meta = m.getAnnotation(FieldMeta.class);  
                if(meta!=null){  
                    SortableField sf = new SortableField(meta,m.getName(),m.getReturnType());  
                    list.add(sf);  
                }  
            }  
            //这种方法是新建FieldSortCom类实现Comparator接口,来重写compare方法实现排序  
//          Collections.sort(list, new FieldSortCom());  
            Collections.sort(list, new Comparator<SortableField>() {  
                @Override  
                public int compare(SortableField s1,SortableField s2) {  
                    return s1.getMeta().order()-s2.getMeta().order();  
//                  return s1.getName().compareTo(s2.getName());//也可以用compare来比较  
                }  
                  
            });  
        }  
        return list;  
          
    }  

}

 

 

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created on 19941115</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

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

/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:SayHiAnnotation   
* @Description:   <p> 自定义注解,用来配置方法</p>
* @Author: - Jason   
* @CreatTime:2018年4月10日 下午9:39:10   
* @Modify By:   
* @ModifyTime:  2018年4月10日
* @Modify marker:   
* @version    V1.0
 */
@Retention(RetentionPolicy.RUNTIME) // 表示注解在运行时依然存在
@Target(ElementType.METHOD) // 表示注解可以被使用于方法上
public @interface SayHiAnnotation {
    
     String paramValue() default "Jason"; 
    // 表示我的注解需要一个参数 名为"paramValue" 默认值为"Jason"
}

 

/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created on 19941115</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:SayHiEmlement   
* @Description:   <p> 要使用SayHiAnnotation的元素所在类 </br> 由于我们定义了只有方法才能使用我们的注解,我们就使用多个方法来进行测试</p>
* @Author: - DaoDou   
* @CreatTime:2018年4月10日 下午9:39:49   
* @Modify By:   
* @ModifyTime:  2018年4月10日
* @Modify marker:   
* @version    V1.0
 */
public class SayHiEmlement {

    // 普通的方法
    public void SayHiDefault(String name,String age){
        System.out.println("Hi, " + name+age);
    }
    
    // 使用注解并传入参数的方法
    @SayHiAnnotation(paramValue="Jack")
    public void SayHiAnnotation(String name,String age){
        System.out.println("Hi, " + name+age);
    }
    
    // 使用注解并使用默认参数的方法
    @SayHiAnnotation
    public void SayHiAnnotationDefault(String name,String age){
        System.out.println("Hi, " + name + age);
    }
}
/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

import java.lang.reflect.Field;

/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:SortableField   
* @Description:   <p> SortableField 可排序字段 </p>
* @Author: - Jason   
* @CreatTime:2018年10月18日 下午9:55:25   
* @Modify By:   
* @ModifyTime:  2018年10月18日
* @Modify marker:   
* @version    V1.0
 */
public class SortableField {
    
    public SortableField(){}  
     
    public SortableField(FieldMeta meta, Field field) {  
        super();  
        this.meta = meta;  
        this.field = field;  
        this.name=field.getName();  
        this.type=field.getType();  
    }  
      
      
    public SortableField(FieldMeta meta, String name, Class<?> type) {  
        super();  
        this.meta = meta;  
        this.name = name;  
        this.type = type;  
    }  
  
  
    private FieldMeta meta;  
    private Field field;  
    private String name;  
    private Class<?> type;  
      
    public FieldMeta getMeta() {  
        return meta;  
    }  
    public void setMeta(FieldMeta meta) {  
        this.meta = meta;  
    }  
    public Field getField() {  
        return field;  
    }  
    public void setField(Field field) {  
        this.field = field;  
    }  
    public String getName() {  
        return name;  
    }  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    public Class<?> getType() {  
        return type;  
    }  
  
    public void setType(Class<?> type) {  
        this.type = type;  
    }  

}
/**
 * <html>
 * <body>
 *  <P> Copyright 1994 JsonInternational</p>
 *  <p> All rights reserved.</p>
 *  <p> Created by Jason</p>
 *  </body>
 * </html>
 */
package cn.ucaner.core.annotation;

import java.lang.reflect.Field;

/**
* @Package:cn.ucaner.core.annotation   
* @ClassName:TestMain   
* @Description:   <p> TestMain </p>
* @Author: - Jason   
* @CreatTime:2018年10月19日 下午3:17:20   
* @Modify By:   
* @ModifyTime:  2018年10月19日
* @Modify marker:   
* @version    V1.0
 */
public class TestMain {

    @FieldMeta(name="Jason")//注解的使用
    private Object obj;
    
    @FieldMeta(name="Andy",description="Intersting")
    private String name;
    
    @FruitName(value="Apple")
    @FieldMeta
    private String profile;
    
    public String getProfile() {
        return profile;
    }

    public void setProfile(String profile) {
        this.profile = profile;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }


    /**
     * @Description: Just for test   注解反射的方式拿到元信息数据
     * @throws Exception void
     */
    public static void main(String[] args) throws Exception{
        
         Field[] fields = TestMain.class.getDeclaredFields();
         for (Field field : fields) {
            System.out.println(field.getName());
             if(field.isAnnotationPresent(FieldMeta.class)){
                 FieldMeta fieldMeta = field.getAnnotation(FieldMeta.class);
                 String str = fieldMeta.name();
                 String description = fieldMeta.description();
                 System.out.println(str);
                 System.out.println(description);
              }if (field.isAnnotationPresent(FruitName.class)) {
                  FruitName fruitName = field.getAnnotation(FruitName.class);
                  System.out.println(fruitName.value());
            }else{
                  //FruitName fruitName = field.getAnnotation(FruitName.class);
                  //System.out.println(fruitName.value());
              }
         }
         
      }

}
//Output
//obj
//Jason
//
//name
//Andy
//Intersting
//profile
//default_name
//
//Apple

 

以上是关于Java Annontation 注解的学习和理解的主要内容,如果未能解决你的问题,请参考以下文章

注解

Annotation 注解快速入门

java annotation有啥作用

注解Annotation实现原理与自定义注解例子

java注解与自定义注解

java注解与自定义注解