• Thinking in Annotation


    Thinking in Java这本书很久前就购买了,打算有时间看一下,因为自己的时间被自己安排的紧张,也没时间看书。黄师傅上次课程讲到了注解的使用和反射的使用,今天打算学习一下注解。该文章参考Thinking in Java的第20章Annotation。

    简单介绍

    注解为我们代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据。

    内置注解:

    JavaSE5内置了3个注解

    • @Override 覆盖超类中的方法,如果不小心拼写错误,或者方法签名对不上覆盖的方法,编译器会发出错误提示
    • @Deprecated 如果程序员使用了注解为它的元素,编译器会发出警告信息
    • @Suppress Warnings 关闭不当的警告信息,在JavaSE5之前版本,也可以使用该注解

    除了这三个注解,Java还提供了四种胡姐,负责新注解的创建,我们将稍后学习。

    当我们创建描述符合性质的类和接口时,一旦其中包含了重复性的工作,那就可以考虑使用注解来简化与自动化该过程,例如

    在EJB中存在很多的额外工作,EJB3.0就是使用注解消除了它们。

    基本语法

    编译器要确保其构造路径上必须有@Test注解的定义,我们可以创建一个通过反射机制来运行testExecute()方法的工具。

    package littlepage.annotation.test1;
    
    public class Testable {
        public void execute(){
            System.out.println("Executing....");
        }
        @Test void testExecute(){execute();}
    }

    备注接的方法与其他方法没有区别,在这个例子中,注解@Test可以与任何修饰符作用于方法,例如public、static或者void。从语法角度看,注解的使用方式几乎与修饰符使用一模一样。

    package littlepage.annotation.test1;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Test {
    }

    除了@符号以外,@Test的定义很像一个空的接口。定义注解,你需要一些元注解(meta-annotation),如@Target和@Retention。@Target用来定义你的注解将用于什么地方(例如一个方法或者一个域),@Retention用来定义注解在哪一个级别可用,在源码中(Source),类文件中(Class)或者运行时(Runtime)

    在注解中,一般会包含一些元素以某些值。当分析处理注解时,程序或者工具可利用这些值。注解的元素看起来很像接口方法,唯一区别是你可以用为其指定默认值。

    没有元素的注解称为标记注解,例如上面的@Test。

    下面死一个简单的注解,我们可以使用它来跟踪项目用例。

    package littlepage.annotation.test1;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface UseCase {
        public int id();
        public String description() default  "no description";
    }

    注意,id和description类似方法的定义,由于便要一起会对id进行类型检查,因此将用例文档追踪数据库与源代码的关联是可靠的。description元素有一个默认值,如果注解某方法没有给出description的值,那么处理器会使用该元素默认值。

    下面一个类中有三个方法被注解的用例

    package littlepage.annotation.test1;
    
    import java.util.List;
    
    public class PasswordUtils {
        @UseCase(id=47,description = "Password must contain at least one numeric")
        public boolean validatePassword(String password){
            return (password.matches("\w*\d\w*"));
        }
    
        @UseCase(id=48)
        public String encryptPassword(String password){
            return new StringBuilder(password).reverse().toString();
        }
    
        @UseCase(id=49,description = "New passwords can't equal previously used ones")
        public boolean checkForNewPassword(List<String> prevPasswords,String password){
            return !prevPasswords.contains(password);
        }
    }

     元注解

    Java目前只内置了3种标准注解,以及四种元注解。元注解负责注解其他注解。

    图:详见Thinking in Java p622

    编写注解处理器

    如果没有用来读取注解的工具,那注解也不刽比注释更加有用。使用注解的过程中,很重要的一个部分是创建和使用注解处理器。Java SE5扩展了反射机制的API,帮助程序员构造这类工具。同时,它还提供了一个外部工具apt帮助程序员解析带有注解的Java代码。

    下面是一个非常简单的注解处理器,我们将用它来读取PasswordUtils类,并使用反射机制查找@UseCase标记。我们为其提供了一组id值,然后它会列出在PasswordUtils中找到的用例,以及缺失的 用例。

    package littlepage.annotation.test1;
    
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    
    public class UseCaseTracker {
        public static void trackUseCases(List<Integer> useCases, Class<?> clazz){
            for (Method m:clazz.getDeclaredMethods()) {
                UseCase uc = m.getAnnotation(UseCase.class);
                if (uc != null) {
                    System.out.println("Found Use Case:" + uc.id() + " " + uc.description());
                    useCases.remove(new Integer(uc.id()));
                }
            }
        }
    
        public static void main(String[] args) {
            List<Integer> useCases=new ArrayList<>();
            Collections.addAll(useCases,47,48,49,50);
            trackUseCases(useCases,PasswordUtils.class);
        }
    }

    这个程序用到了两个反射的方法:getDeclaredMethods()和getAnnotation(),它们都属于AnnotatedElement接口(Class,Method和Field等类都实现了该接口)。getAnnoation()方法返回指定类型的注解对象。在这里就是UseCase。如果被注解方法上没没有该类型的猪价,则返回null值。然后我们通过调用id和description的方法从返回的对象中提取元素的值。

    注解元素

    标签@UeCase由UseCase.java定义,其中包含int元素id,以及一个String元素description,注解元素可用类型如下所示:

    • 所有基本类型(int,float,boolean等)
    • String
    • Class
    • enum
    • Annotation
    • 以上类型的数组

    如果你使用其他类型,那么编译器就会报错。也不允许使用任何包装类型,不过由于自动打包机制,这个算不上限制。注解也可以作为元素类型,稍后,我们可以看到,这是一个很有用的技巧。

    (浅识注解,博主学习速度太慢,需要慢慢消化 )

  • 相关阅读:
    String类型操作命令及api使用
    回顾Redis基础
    kibana6 安装
    elasticsearch安装
    flink 异常
    Scala异常
    idea配置
    mysql error 1577解决
    Hbase与phoenix关联
    CS61b lab4打卡
  • 原文地址:https://www.cnblogs.com/littlepage/p/11188275.html
Copyright © 2020-2023  润新知