zoukankan      html  css  js  c++  java
  • 注解

    一、创建注解

    注解是一种手段,它可以给程序添加一些信息,用字符@开头,这些信息用于修饰它后面紧挨着的其他代码元素,比如类、接口、字段、方法、参数、构造方法等。注解本身只是一种标记,不会改变当前代码的行为,类似标记接口的作用,但是它可以被编译器、程序运行时和其他工具使用,可以被用于增强或修改代码行为等。

    我们可以像定义一个接口一样定义注解:

        @Target(ElementType.METHOD)  //声明注解的目标
        @Retention(RetentionPolicy.SOURCE)  //声明注解信息保留到什么时候
        @interface TestAnnotation{  //定义注解
            String value();  //定义注解的参数,可以有多个
        }

    @interface 为定义注解的关键字,和定义接口相似;

    @Target和@Retention是两个元注解,其中@Target声明该注解的作用目标,有以下几种:

    • TYPE——表示适用于类、接口或枚举
    • FIELD——字段,包括枚举常量
    • METHOD——方法
    • PARAMETER——方法中的参数
    • CONSTRUCTOR——构造方法
    • LOCAL_VARIABLE——本地变量
    • MODULE——模块(java 9引入)

    目标可以有多种类型,用{,}隔开,默认是所有类型。

    @Retention表示注解信息保留到什么时候,有以下三种:

    • SOURCE——只在源代码中保留,编译器将代码编译成字节码文件后就会丢掉
    • CLASS——保留到字节码文件中,但Java虚拟机将class文件加载到内存是不一定在内存中保留
    • RUNTIME——一直保留到运行时

    只能选择一种,默认是CLASS。

    可以为注解定义一些参数,如上例中的Sting value(),其中String 是参数类型,value是参数名,也可以指定默认值(如没有声明默认值,使用时必须赋值):

    String value() default "v0";

    上面注解的使用方法如下:

        @TestAnnotation(value = "v1")
        public void operation() {...}

    如果只有一个参数,且名称是value时可以省略参数名:

        @TestAnnotation("v1")
        public void operation() {...}

    二、查看注解

     创建了注解并在代码中使用,并不会影响代码的行为。要影响代码行为首先要能够查看注解信息,我们一般使用反射机制在运行时查看和利用注解信息。反射中有很多与注解相关的方法:

       //判断是否有指定类型的注解
        public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
    
       //获取该元素所有注解
        public Annotation[] getAnnotations() {}
    
        //获取该元素指定注解
        public <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {}
        
        //获取参数类型注解,仅Method和Constructor元素有此方法
        public Annotation[][] getParameterAnnotations() {}

    下面利用反射查看并调用带有特定类型注解的方法:

        public static <T> void parseMethod(Class<T> clazz) {
            try {
                T obj = clazz.newInstance();  //创建反射类实例
                for (Method method : clazz.getDeclaredMethods()) {  //获取所有声明的方法
                    MyMethodAnnotation methodAnnotation = method.getAnnotation(MyMethodAnnotation.class);  //获取每个方法的MyMethodAnnotation类型注解信息
                    if (methodAnnotation != null) {
                        // 通过反射调用带有此注解的方法,并引用注解参数uri
                        method.invoke(obj, methodAnnotation.uri());
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

    三、应用注解

    下面以格式化输出为例讲解注解的实战用法。

    如果我们需要打印一个对象的变量信息,通常是调用它的toString方法,但是往往不能达到我们想要的信息展示效果,我们需要定制toString方法,如果有多个不同对象,则需要定制每个对象对应类的toString方法。

    使用注解可以简化这一过程,首先定义两个注解:

    //表示变量名称
    @Retention(RUNTIME)
    @Target(FIELD)
    public @interface Label {
        String value() default "";
    }
    
    //表示日期变量格式
    @Retention(RUNTIME)
    @Target(FIELD)
    public @interface Format {
        String pattern() default "yyyy-MM-dd HH:mm:ss";
        String timezone() default "GMT+8";
    }

    然后使用这两个注解:

        static class Student {
            @Label("姓名")
            String name;
    
            @Label("出生日期")
            @Format(pattern = "yyyy/MM/dd")
            Date born;
    
            @Label("分数")
            double score;
        }

    定义一个SimpleFormatter类在运行时查看并使用注解信息对输出格式化:

    public class SimpleFormatter {
        public static String format(Object obj) {
            try {
                Class<?> cls = obj.getClass();  //通过实例获取Class类
                StringBuilder sb = new StringBuilder();
                for (Field f : cls.getDeclaredFields()) {  //获取所有变量
                    if (!f.isAccessible()) {  //取消访问限制
                        f.setAccessible(true);
                    }
                    Label label = f.getAnnotation(Label.class);  //获取Lable注解
                    String name = label != null ? label.value() : f.getName();  //读取变量名称
                    Object value = f.get(obj);  //获取变量值
                    if (value != null && f.getType() == Date.class) {
                        value = formatDate(f, value);  //如果是日期
                    }
                    sb.append(name + ":" + value + "
    "); //格式化
                }
                return sb.toString();
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }
        }
    
    }

    使用方法如下:

        public static void main(String[] args) throws ParseException {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            Student zhangsan = new Student("张三", sdf.parse("1990-12-12"), 80.9d);
            
            System.out.println(SimpleFormatter.format(zhangsan));
    }

    输出结果:

    姓名:张三
    出生日期:1990/12/12
    分数:80.9

    四、总结

      注解提升了Java语言的表达能力,有效地实现了应用功能和底层功能的分离,框架/库的程序员可以专注于底层实现,借助反射实现通用功能,提供注解给应用程序员;应用程序员可以专注于应用功能开发,通过简单的声明式注解与框架/库进行协作。

  • 相关阅读:
    Spring中Quartz的配置
    通用表格打印1
    使用Lucene.Net实现全文检索
    DIV CSS 网页兼容全搞定 (IE6 IE7 IE8 IE9 火狐 谷歌)
    Code128 条码生成
    URL参数Base64解密和解密
    JQuery EasyUI 中文API
    linux 下mysql命令 (授权用户 和 基本操作)
    python操作MySQL数据库
    GridView分组,统计,排序的解决方案
  • 原文地址:https://www.cnblogs.com/not2/p/11159122.html
Copyright © 2011-2022 走看看