好处:

能够读懂别人的代码,特别是框架相关的代码;

让编程更加简洁,代码更加清晰。

使用自定义注解解决问题!!

Java1.5版本引入。

Java中的常见注解

  • @Override:告诉使用者及编译器,该方法覆盖了父类或接口中的同名方法
  • @Deprecated:表示该方法已经过时了。
  • @Suppvisewarnings:忽略deprecated给出的警告。
  • 常见第三方注解:
    • Spring: @Autowired, @Service, @Repository
    • Mybatis: @InsertProvider, @UpdateProvider, @Options

注解分类

  • 按照运行机制分:

    • 源码注解:注解只在源码中存在,编译成class文件就不存在了
    • 编译时注解:注解在源码和.class文件中都存在
    • 运行时注解 :在运行阶段还起作用,甚至会影响运行逻辑的注解 如@Autowired注解
  • 按照来源分:
    • 来自JDK的注解
    • 来自第三方的注解
    • 自己定义的注解
  • 元注解:注解的注解

自定义注解

  • 语法要求

    • 成员类型是受限的,合法的类型包括原始类型及String,Class,Annotation,Enumeration;
    • 如果注解只有一个成员,则成员们必须取名为value(),在使用时可以忽略成员名和赋值号(=);
    • 注解类可以没有成员,没有成员的注解类成为标识注解;
  • 元注解(注解的注解)
    • @Target(……)
    • @Retention:生命周期(SOURCE:只在源码显示编译时丢弃;CLASS:编译时会记录到class中,运行时忽略;RUNTIME:运行时存在,可以通过反射读取)
    • @Inherited:允许子类继承,只能在类或者抽象类间继承,接口是不会继承的。而且继承时只是类的继承,类中的方法并不会继承。
    • @Documented:生成javadoc时会包含信息。
      • 到处一个Javadoc:在工程上点击Export->javadoc->设置路径,通过index.html即可查看你导出的Javadoc
  • 使用自定义注解

解析注解

  • 概念:通过反射获取类、函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑。
  • //实例:拿到类名字的解释
    public class ParseAnn {
    public static void main(String[] args) {
    //1.使用类加载器加载类
    try {
    Class c = Class.forName("com.ann.test.Child");
    //2.找到类上面的注解
    boolean isExist = c.isAnnotationPresent(Description.class);
    if(isExist) {
    //3.拿到注解实例
    Description d = (Description) c.getAnnotation(Description.class);
    System.out.println(d.value());
    }
    //4.找到方法上的注解
    Method[] ms = c.getMethods();
    for(Method m : ms) {
    boolean isMExist = m.isAnnotationPresent(Description.class);
    if(isMExist) {
    Description d = (Description) m.getAnnotation(Description.class);
    System.out.println(d.value());
    }
    } //另外一种解析方法
    for(Method m : ms) {
    Annotation[] as = m.getAnnotations();
    for(Annotation a : as) {
    if(a instanceof Description) {
    Description d = (Description)a;
    System.out.println(d.value());
    }
    }
    } } catch (ClassNotFoundException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }
  • //Child.java信息
    @Description("I am class annotation")
    public class Child implements Person { @Override
    @Description("I am method annotation")
    public String name() {
    // TODO Auto-generated method stub
    return null;
    } @Override
    public int age() {
    // TODO Auto-generated method stub
    return 0;
    } @Override
    public void sing() {
    // TODO Auto-generated method stub } }

实践

  • 项目取自一个公司的持久层框架,用来代替Hibernate的解决方案,核心代码就是通过注解来实现的。
  • 需求:
    • 1.有一张用户表,字段包括用户ID、用户名、昵称、年龄、性别、所在城市、邮箱、手机号。
    • 2.方便的对每个子弹或字段的组合条件进行检索,并打印出SQL。
    • 使用方式要足够简单。
  • private static String query(Object f) {
    StringBuilder sb = new StringBuilder();
    //1.获取到class
    Class c = f.getClass();
    //2.获取到table的名字
    boolean exist = c.isAnnotationPresent(Table.class);
    if(!exist)
    return null;
    Table t = (Table) c.getAnnotation(Table.class);
    String tableName = t.value();
    sb.append("select * from ").append(tableName).append(" where 1=1 ");
    //3.遍历所有的字段
    Field[] fArray = c.getDeclaredFields();
    for(Field field : fArray) {
    //4. 处理每个字段对应的SQL
    //4.1 拿到字段名
    boolean fe = field.isAnnotationPresent(Column.class);
    if(!fe)
    continue;
    // Column column = field.getAnnotation(Column.class);
    // String columnName = column.value();
    //4.2拿到字段值
    String fieldName = field.getName();
    String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() +
    fieldName.substring(1);
    Object fieldValue = null;
    try {
    Method getMethod = c.getMethod(getMethodName);
    fieldValue = getMethod.invoke(f);
    } catch (Exception e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    //4.3拼装SQL
    if(fieldValue == null ||
    (fieldValue instanceof Integer && (Integer)fieldValue == 0))
    continue;
    if(fieldValue instanceof String) {
    if(((String) fieldValue).contains(",")) {
    String[] values = ((String) fieldValue).split(",");
    sb.append("and ").append(fieldName).append(" in(");
    for(String v : values) {
    sb.append("'").append(v).append("',");
    }
    sb.deleteCharAt(sb.length()-1);
    sb.append(")");
    }
    else
    sb.append("and ").append(fieldName).append("='")
    .append(fieldValue).append("'");
    }
    else
    sb.append("and ").append(fieldName).append("=").append(fieldValue);
    } return sb.toString();
    }

总结

  • 注解的作用范围@Target和生命周期@Retention

    • 作用范围包括:包、类、字段、方法、方法的参数和局部变量
    • 生命周期:源文件SOURCE、编译CLASS、运行RUNTIME
  • 等读懂注解
  • 在实际项目中用注解解决问题,并能自定义注解

有用的Java注解的更多相关文章

  1. Java 注解 入门

    这几天在学习Spring3.x,发觉现在许多框架都用上了java注解功能,然后自己就对java注解这方面初步学习了一下. 首先,注解跟注释不是一个意思,也根本不是同一个事物. 注释就是我们平常平常中对 ...

  2. Java注解(2)-注解处理器(运行时|RetentionPolicy.RUNTIME)

    如果没有用来读取注解的工具,那注解将基本没有任何作用,它也不会比注释更有用.读取注解的工具叫作注解处理器.Java提供了两种方式来处理注解:第一种是利用运行时反射机制:另一种是使用Java提供的API ...

  3. Java 注解指导手册 – 终极向导

    原文链接 原文作者:Dani Buiza 译者:Toien Liu  校对:深海 编者的话:注解是java的一个主要特性且每个java开发者都应该知道如何使用它. 我们已经在Java Code Gee ...

  4. Java注解处理器

    Java注解处理器 2015/03/03 | 分类: 基础技术 | 0 条评论 | 标签: 注解 分享到:1 译文出处: race604.com   原文出处:Hannes Dorfmann Java ...

  5. Java注解解析-搭建自己的注解处理器(CLASS注解使用篇)

    该文章是继Java注解解析-基础+运行时注解(RUNTIME)之后,使用注解处理器处理CLASS注解的文章.通过完整的Demo例子介绍整个注解处理器的搭建流程以及注意事项,你将知道如何去搭建自己的注解 ...

  6. java注解使用总结

    2005年,sun公司推出了jdk1.5,同时推出的注解功能吸引了很多人的目光,使用注解编写代码,能够减轻java程序员繁琐配置的痛苦. 使用注解可以编写出更加易于维护,bug更少的代码. 注解是什么 ...

  7. 夯实Java基础系列15:Java注解简介和最佳实践

    Java注解简介 注解如同标签 Java 注解概述 什么是注解? 注解的用处 注解的原理 元注解 JDK里的注解 注解处理器实战 不同类型的注解 类注解 方法注解 参数注解 变量注解 Java注解相关 ...

  8. Java注解简单学习

    注解(也被称作元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们在稍后某个时刻可以很方便的使用这些数据,其在一定程度上将元数据与源代码文件结合在一起,而不是保存在外部文档中. 注解使我们可以 ...

  9. Java 注解指导手册(下)

    9. 自定义注解   正如我们之前多次提及的,可以定义和实现自定义注解.本章我们即将探讨. 首先,定义一个注解:   public @interface CustomAnnotationClass   ...

随机推荐

  1. Linux系统定时任务crond那些事

    1 Linux系统定时任务 1.1 定时任务介绍 1.1.1 Crond是什么? Crond是linux系统中用来定期执行命令或指定程序任务的一种服务或软件.Centos5/ linux系统安装完操作 ...

  2. jquery点击按钮复制内容

    做移动端的项目遇到一个需求要点击按钮复制dom里的内容,看了很多资料显示必须textarea或者input里的内容才能简单复制,还有就是用插件的了,最终都因为遇到各种问题放弃,最终选择了最简单的点击复 ...

  3. grafana使用Prometheus数据源监控mongo数据库

    数据库改用mongo后,监控需求就需要整合进grafana里,由于一直在坚持docker化部署,那么此次也不例外. 1. 安装Prometheus: What is Prometheus? Prome ...

  4. Redis面试问题

    下面列出的这些其中有一些是我面试时遇到的,但是当时自己还不会,所以在网站上找了以下,然后整理出来,加强记忆 感谢码洞将这些问题整理出来: Redis有哪些数据结构? 字符串String.字典Hash. ...

  5. iWebShop产品功能技术优势有什么?

    iwebshop基于iweb si 框架开发,在获得iweb si 技术平台支持的条件下,iwebshop可以轻松满足用户量级百万至千万级的大型电子商务网站的性能要求.站点的集群与分布式技术(分布式计 ...

  6. CentOS下安装pip

    CentOS下安装pip 通常情况下使用命令: yum -y install pip 也有可能报错,无法安装.这是应该使用第二种方法. 1.首先需要先安装扩展源EPEL: yum -y install ...

  7. docker理论基础

    Namespaces 命名空间(namespaces)是 Linux 为我们提供的用于分离进程树.网络接口.挂载点以及进程间通信等资源的方法.在日常使用 Linux 或者 macOS 时,我们并没有运 ...

  8. 11 非阻塞套接字与IO多路复用(进阶)

    1.非阻塞套接字 第一部分 基本IO模型 1.普通套接字实现的服务端的缺陷 一次只能服务一个客户端! 2.普通套接字实现的服务端的瓶颈!!! accept阻塞! 在没有新的套接字来之前,不能处理已经建 ...

  9. makefile = 与 := 的区别

    “=” make会将整个makefile展开后,再决定变量的值.也就是说,变量的值将会是整个makefile中最后被指定的值.看例子: x = foo            y = $(x) bar  ...

  10. (数据科学学习手札32)Python中re模块的详细介绍

    一.简介 关于正则表达式,我在前一篇(数据科学学习手札31)中已经做了详细介绍,本篇将对Python中自带模块re的常用功能进行总结: re作为Python中专为正则表达式相关功能做出支持的模块,提供 ...