zoukankan      html  css  js  c++  java
  • Java学习:Annotation注解

    Annotation不算常用的技术,早前用它写了一些玩意儿,过了一年又忘干净了,今天写点东西记下来,以备再忘之需。

    java.lang.annotation,接口 Annotation。对于Annotation,是Java5的新特性,JDK5引入了Metedata(元数据)很容易的就能够调用Annotations。Annotations提供一些本来不属于程序的数据,比如:一段代码的作者或者告诉编译器禁止一些特殊的错误。An annotation 对代码的执行没有什么影响。Annotations使用@annotation的形式应用于代码:类(class),属性(attribute),方法(method)等等。一个Annotation出现在上面提到的开始位置,而且一般只有一行,也可以包含有任意的参数。

    ——————百度百科

    Annotation是什么,上面说得很清楚了,下面重点说,它怎么写,和有什么用。

     一、Annotation的基本写法

    /**
     * @author caiyu
     * @date 2014-1-21
     */
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.METHOD)
    public @interface DataSchemaConfig {
        String type() default "get";
        String value();
    }

    1、DataSchemaConfig为Annotation的名称

    2、 @Retention 表示该Annotation的保留级别

    分别以下三种:

    RetentionPolicy.RUNTIME

    会记录在CLASS里,同时会在运行时保留该注解,以使其可以被反射读取。

    RetentionPolicy.SOURCE

    只存在于源码里,会被编译器抛弃

    RetentionPolicy.CLASS

    会被编译器记录在CLASS文件中,但虚拟机不会在运行时保留它。该选项是默认选项

    3、@Target表示该Annotation的影响范围,如下所示:

    package java.lang.annotation;
    
    /**
     * A program element type.  The constants of this enumerated type
     * provide a simple classification of the declared elements in a
     * Java program.
     *
     * <p>These constants are used with the {@link Target} meta-annotation type
     * to specify where it is legal to use an annotation type.
     *
     * @author  Joshua Bloch
     * @since 1.5
     */
    public enum ElementType {
        /** Class, interface (including annotation type), or enum declaration */
        TYPE,
    
        /** Field declaration (includes enum constants) */
        FIELD,
    
        /** Method declaration */
        METHOD,
    
        /** Parameter declaration */
        PARAMETER,
    
        /** Constructor declaration */
        CONSTRUCTOR,
    
        /** Local variable declaration */
        LOCAL_VARIABLE,
    
        /** Annotation type declaration */
        ANNOTATION_TYPE,
    
        /** Package declaration */
        PACKAGE
    }

    4、内容组织形式

    String type() default "get";

     这段声明里,String为成员类型,type为成员名称(必须写上括号),default "get"表示缺省指为"get"

    5、使用见如下示例代码

      

    /**
     * @author caiyu
     * @date 2014-1-22
     */
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.TYPE)
    public @interface DataType {
        public String value() default "map";
    }
    
    
    
    @DataType(value = "bean")
    public class MapModel {
        private Map<String, Object> o = new HashMap<String, Object>();
    
        @GET
        public Object get(String key) {
            return o.get(key);
        }
    
        @PUT
        public void put(String key, Object value) {
            o.put(key, value);
        }
    }
    DataType 这个Annotation被声明为Runtime以及TYPE,所以它可以被用于注解MapModel这个类。
    括号里的value="bean",则是为其value赋值1,同时由于value是个特殊成员,可以写作
    @DataType("bean")

      如果写作

    @DataType

      则value会使用默认值"map"

    6、数组形式的成员类型的使用

     把上面的内容改成下面的格式:

    String[] value() default "map";

    之前的这种写法@DataType("bean")仍然是合法的

      同时可以写作@DataType({"map","bean"})

     二、Annotaion的用途

    在介绍@Retention的时候,其实已经说明了Annotation的三种类型了,SOURCE和CLASS类型使用很少,如果你不是需要自己写一个Java Compiler或者Editor,基本用不上。

    这里重点说说RUNTIME类型。

    我们知道,RUNTIME会被保存在CLASS文件中,而且其中记录的信息可以通过反射来获取到,于是可以利用这点实现一些方便的配置(比如Spring和Hibernate就是利用这点)。

     来看看一个MapModel类:

    @DataType
    public class MapModel {
        private Map<String, Object> o = new HashMap<String, Object>();
    
        @get
        public Object getProperty(String key) {
            return o.get(key);
        }
    
        @put
        public void putProperty(String key, Object value) {
            o.put(key, value);
        }
    
        public String toString() {
            return o.toString();
        }
    }

    可以看到,MapModel标记了三个注解,分别是DataType和get、put

    下面的代码,是用来把该Model和org.dom4j.Element相互转换的,注意只能参考,并不完整:

    /**
         * 序列化注解类型
         * 
         * @param content
         * @param schema
         * @return
         */
        private Element serialMapType(Object content, IDataSchema<?> schema) {
            DataType type = schema.getType().getAnnotation(DataType.class);
            if (type != null && type.value() == DataTypeValue.MAP) {
                Element root = DocumentFactory.getInstance().createElement(
                        schema.getName());
    
                Method getMethod = extraMethodByAnnotation(schema.getType(),
                        get.class);
                if (getMethod == null)
                    throw new InvalidAnnotationConfigException(
                            "Invalid annotation class: "
                                    + schema.getType().getName());
                try {
                    for (Entry<String, IDataSchema<?>> field : schema
                            .getFieldEntrySet()) {
                        Object o = getMethod.invoke(content, field.getValue()
                                .getId());
                        Element e = save(o, field.getValue());
                        root.add(e);
                    }
                    return root;
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    throw new InvalidAnnotationConfigException(
                            "Invalid put method : " + getMethod.getName());
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
    
            }
    
            return null;
        }
    
    
    
        /**
         * 反序列化注解类型数据
         * 
         * @param persistentTarget
         * @param schema
         * @return
         */
        private Object deserialMapType(Element persistentTarget,
                IDataSchema<?> schema) {
            Object instance = null;
            DataType type = schema.getType().getAnnotation(DataType.class);
            if (type != null && type.value() == DataTypeValue.MAP) {
                Method putMethod = extraMethodByAnnotation(schema.getType(),
                        put.class);
                if (putMethod == null)
                    throw new InvalidAnnotationConfigException(
                            "Invalid annotation class: "
                                    + schema.getType().getName());
                try {
                    instance = schema.getType().newInstance();
                    for (Entry<String, IDataSchema<?>> field : schema
                            .getFieldEntrySet()) {
                        Element e = persistentTarget.element(field.getValue()
                                .getName());
                        Object v = load(e, field.getValue());
                        putMethod.invoke(instance, new Object[] {
                                field.getValue().getId(), v });
                    }
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (IllegalArgumentException e) {
                    throw new InvalidAnnotationConfigException(
                            "Invalid put method : " + putMethod.getName());
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
            return instance;
        }
        /**
         * 抽取含有指定注解的方法
         * 
         * @param type
         * @param annotationClass
         * @return
         */
        private Method extraMethodByAnnotation(Class<?> type,
                Class<? extends Annotation> annotationClass) {
            for (Method method : type.getDeclaredMethods()) {
                Annotation t = method.getAnnotation(annotationClass);
                if (t != null) {
                    return method;
                }
    
            }
            return null;
        }
  • 相关阅读:
    java中变量的内存分配
    类加载器的双亲委派机制
    缓存行对齐
    缓存一致性与MESI协议
    Mysql优化之join优化
    MySQL crc32 & crc64函数 提高字符串查询效率
    线程不安全
    学习爱上 systemd
    Ubuntu如何备份和恢复系统
    redis报错overcommit_memory is set to 0
  • 原文地址:https://www.cnblogs.com/anrainie/p/3528146.html
Copyright © 2011-2022 走看看