目录:

  • 一. 什么是Annotation
  • 二. Annotation的作用
    • 2.1 编译器使用到的注解
    • 2.2 .class文件使用到的注解
    • 2.3 运行期读取的注解
  • 三. 定义Annotation
    • 3.1 元注解
    • 3.2 定义注解小结
  • 四. Annotation处理
  • 五. 总结

一. 什么是Annotation

我们在平时的开发过程中看到很多如@Override,@SuppressWarnings,@Test等样式的代码就是注解,注解是放到类、构造器、方法、属性、参数前的标记。

二. Annotation的作用

给某个类、方法..添加了一个注解,这个环节仅仅是做了一个标记,对代码本身并不会造成任何影响,需要后续环节的配合,需要其他方法对该注解赋予业务逻辑处理。就如同我们在微信上发了一个共享定位,此时并没有什么用,只有当后面其他人都进入了这个共享定位,大家之间的距离才能明确,才知道该怎么聚在一起。

注解分为三类:

2.1 编译器使用到的注解

如@Override,@SuppressWarnings都是编译器使用到的注解,作用是告诉编译器一些事情,而不会进入编译后的.class文件。

@Override:告诉编译器检查一下是否重写了父类的方法;

@SuppressWarnings:告诉编译器忽略该段代码产生的警告;

对于开发人员来说,都是直接使用,无需进行其他操作

2.2 .class文件使用到的注解

需要通过工具对.class字节码文件进行修改的一些注解,某些工具会在类加载的时候,动态修改用某注解标注的.class文件,从而实现一些特殊的功能,一次性处理完成后,并不会存在于内存中,都是非常底层的工具库、框架会使用,对于开发人员来说,一般不会涉及到。

2.3 运行期读取的注解

一直存在于JVM中,在运行期间可以读取的注解,也是最常用的注解,如Spring的@Controller,@Service,@Repository,@AutoWired,Mybatis的@Mapper,Junit的@Test等,这类注解很多都是工具框架自定义在运行期间发挥特殊作用的注解,一般开发人员也可以自定义这类注解。

三. 定义Annotation

我们使用@interface来定义一个注解

/**
* 定义一个Table注解
*/
public @interface Table {
String value() default "";
}
/**
* 定义一个Colum注解
*/
public @interface Colum {
String value() default "";
String name() default "";
String dictType() default "";
}

这样就简单地将一个注解定义好了

我们上面定义的注解主要用到了String类型,但实际上还可以是基本数据类型(不能为包装类)、枚举类型。

注解也有一个约定俗成的东西,最常用的参数应该命名为value,同时一般情况下我们都会通过default参数设置一个默认值。

但这样是不是就满足于我们的使用了呢,我想把@Table注解仅用于类上,@Colum注解仅用于属性上,怎么办?而且开始提到的三类注解,一般开发人员用的都是运行期的注解,那我们定义的是吗?

要回答这些问题,就需要引入一个概念“元注解”。

3.1 元注解

可以修饰注解的注解即为元注解,Java已经定义了一些元注解,我们可以直接使用。

3.1.1 @Target

顾名思义指定注解使用的目标对象,参数为ElementType[]

public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}

而下面是ElementType枚举中定义的属性,不设置Target的时候,除了TYPE_PARAMETER,TYPE_USE,其他地方都相当于配置上了。

public enum ElementType {
/** 通过ElementType.TYPE可以修饰类、接口、枚举 */
TYPE, /** 通过ElementType.FIELD可以修饰类属性 */
FIELD, /** 通过ElementType.METHOD可以修饰方法 */
METHOD, /** 通过ElementType.PARAMETER可以修饰参数(如构造器或者方法中的) */
PARAMETER, /** 通过ElementType.CONSTRUCTOR可以修改构造器 */
CONSTRUCTOR, /** 通过ElementType.LOCAL_VARIABLE可以修饰方法内部的局部变量 */
LOCAL_VARIABLE, /** 通过ElementType.ANNOTATION_TYPE可以修饰注解 */
ANNOTATION_TYPE, /** 通过ElementType.PACKAGE可以修饰包 */
PACKAGE, /**
* 可以用在Type的声明式前
*
* @since 1.8
*/
TYPE_PARAMETER, /**
* 可以用在所有使用Type的地方(如泛型、类型转换等)
*
* @since 1.8
*/
TYPE_USE
}

我们主要说一下ElementType.PACKAGE和1.8添加的ElementType.TYPE_PARAMETER和ElementType.TYPE_USE

ElementType.PACKAGE

@Target(ElementType.PACKAGE)
public @interface Table {
String value() default "";
}

含义是用来修饰包,但我们用来修饰包的时候却提示错误

我们按照提示创建package-info.java文件,这里需要注意一下,通过IDE 进行new --> Java Class是创建不了的,需要通过new File文件创建

@Table
package annotation;
class PackageInfo {
public void hello() {
System.out.println("hello");
}
}

ElementType.TYPE_PARAMETER和ElementType.TYPE_USE

这两个一起说,因为它们有相似之处。都是Java1.8后添加的

@Target(ElementType.TYPE_USE)
public @interface NoneEmpty {
String value() default "";
}
@Target(ElementType.TYPE_PARAMETER)
public @interface NoneBlank {
String value() default "";
}

很明显使用ElementType.TYPE_PARMETER修饰的注解@NoneBlank无法在泛型使用的时候编译通过,仅能用于类的泛型声明,而通过ElementType.TYPE_USE修饰的注解@NoneEmpty可以。

3.1.2 @Retention

可以用于定义注解的生命周期,参数为枚举RetentionPolicy,包括了SOURCE,CLASS,RUNTIME

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
public enum RetentionPolicy {
/**
* 仅存在于源代码中,编译阶段会被丢弃,不会包含于class字节码文件中.
*/
SOURCE, /**
* 【默认策略】,在class字节码文件中存在,在类加载的时被丢弃,运行时无法获取到
*/
CLASS, /**
* 始终不会丢弃,可以使用反射获得该注解的信息。自定义的注解最常用的使用方式。
*/
RUNTIME
}

3.1.3 @Documented

表示是否将此注解的相关信息添加到javadoc文档中

3.1.4 @Inherited

定义该注解和子类的关系,使用此注解声明出来的自定义注解,在使用在类上面时,子类会自动继承此注解,否则,子类不会继承此注解。注意,使用@Inherited声明出来的注解,只有在类上使用时才会有效,对方法,属性等其他无效。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Person {
String value() default "man";
}
@Person
public class Parent {
}
//子类也拥有@Person注解
class Son extends Parent { }

3.2 定义注解小结

用@interface定义注解

可以添加多个参数,核心参数按约定用value,为每个参数可以设置默认值,参数类型包括基本类型、String和枚举

可以使用元注解来修饰注解,元注解包括多个,必须设置@Target@Retention@Retention一般设置为RUNTIME

四. Annotation处理

我们前面已经提到光配置了注解,其实没有作用,需要通过相应的代码来实现该注解想要表达的逻辑。

注解定义后也是一种class,所有的注解都继承自java.lang.annotation.Annotation,因此,读取注解,需要使用反射API。

//定义的注解
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Colum {
String value() default "";
//用于表示某个属性代表的中文含义
String name() default "";
}

用注解@Colum来修饰某个类的属性

public class Person {

    @Colum(name = "姓名")
private String name; @Colum(name = "性别")
private String gender; @Colum(name = "年龄")
private int age; @Colum(name = "住址")
private String address; public String getName() {return name;}
public void setName(String name) {this.name = name;}
public String getGender() {return gender;}
public void setGender(String gender) {this.gender = gender;}
public int getAge() {return age;}
public void setAge(int age) {this.age = age;}
public String getAddress() {return address;}
public void setAddress(String address) {this.address = address;}
}

通过反射读取这个类的所有字段的中文含义,并保存到list中,然后打印出来

public static void main(String[] args) throws ClassNotFoundException {
List<String> columNames = new ArrayList<>();
Class clazz = Class.forName("annotation.Person");
//获取Person类所有属性
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields){
//获取该属性的Colum注解
Colum colum = field.getAnnotation(Colum.class);
//或者可以先判断有无该注解
field.isAnnotationPresent(Colum.class);
//将该属性通过注解配置好的中文含义取出来放到集合中
columNames.add(colum.name());
} //打印集合
columNames.forEach((columName) -> System.out.println(columName));
}

结果如下:

姓名
性别
年龄
住址

比如我们有一些常见的应用场景,需要把网站上的列表导出成excel表格,我们通过注解的方式把列名配置好,再通过反射读取实体需要导出(是否需要导出,也可通过注解配置)的每个字段的值,从而实现excel导出的组件。

五. 总结

本文只是抛砖引玉地讲解了注解的基本概念,注解的作用,几种元注解的功用以及使用方法,并通过一个简单的例子讲解了一下注解的处理,并不全面,文中通过Field讲解了注解的基本Api,但注解还可以修饰类、构造器、方法等,也有相对应的注解处理方法,大家可自行查一下API手册相关内容,大同小异,有不对之处,请批评指正,望共同进步,谢谢!


关注微信公众号【程序员的梦想】,专注于Java,SpringBoot,SpringCloud,微服务,Docker以及前后端分离等全栈技术。

一起来看一下Java中的Annotation注解的更多相关文章

  1. Java基础笔记 – Annotation注解的介绍和使用 自定义注解

    Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 |  被围观 25,969 views+ 1.Anno ...

  2. Java中常见的注解

    Java中常见的注解 1.JDK自带的注解@Override  @Deprecated  @Suppvisewarnings 常见第三方注解 Spring:@Autowired  @Service  ...

  3. Java中的元注解

    注解为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据. 通过使用注解,我们可以将这些元数据保存在Java源代码中,并利用annotation API为自己的 ...

  4. Java中的Annotation(2)----Annotation工作原理

    Java中的Annotation(2)----Annotation工作原理 分类: 编程语言2013-03-18 01:06 3280人阅读 评论(6) 收藏 举报 上一篇文章已经介绍了如何使用JDK ...

  5. Java中万恶的注解

    本文由码农网 – 孙腾浩原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 当Java 1.5引入注解,企业开发者对简化EJB和其他企业产品开发抱有很大期望.可以看一看同一时期的一篇文章 ...

  6. java中的Annotation

    java中包含5个基本的Annotation: @Override @Deprecated @SuppressWarnings @SafeVarargs @FunctionalInterface …… ...

  7. java中所有开源注解收集

    @resource: resource全名为@Resource ,用来激活一个命名资源(namedresource)的依赖注入,在JavaEE应用程序中,该注解被典型地转换为绑定于JNDI conte ...

  8. Java中的自定义注解

    ## 元注解 要声明一个注解, 我们需要元注解, 元注解是指注解的注解,包括@Retention, @Target, @Document, @Inherited. @Retention 注解的保留位置 ...

  9. 来看一下Java中“-”与equeals的区别

    简介: == ==是比较两个变量的值,如果是基本数据类型,那么就是比较的基本数据的大小值 情况一 int a=1; int b=1; System.out.println(a==b); 以上图中:== ...

随机推荐

  1. NetCore+AutoMapper多个对象映射到一个Dto对象

    目录 一. 定义源映射类和被映射类DTO二.注入AutoMapper三.配置映射四.写测试 一.定义源映射对象 为了体现AutoMapper映射特性,在SocialAttribute中的Name属性没 ...

  2. input和btton的相互使用————小程序

    input和btton的相互使用----小程序 index.js data: { userxx:'1111', }, changeSum(){ // this.data.userxx="ch ...

  3. zookeeper伪集群

    Zookeeper运行需要java环境,需要安装jdk,建议本地下载好需要的安装包然后上传到服务器上面,服务器上面下载速度太慢. 上传 [root@192 ~]# java -version java ...

  4. shiro+spring

    公司自用的管理系统使用了shiro,但是对于这个登录页面跳转.登录的过程逻辑以及登录成功或者失败的跳转页面一直不理解,查看相关文档资料,整理出一些结果并本地调试测试,记录下备以后回顾之用. 对于spr ...

  5. 使用JSP+Servlet+Jdbc+Echatrs实现对豆瓣电影Top250的展示

    使用JSP+Servlet+Jdbc+Echatrs实现对豆瓣电影Top250的展示 写在前面: 有的小伙伴,会吐槽啦,你这个标题有点长的啊.哈哈 ,好像是的!不过,这个也是本次案例中使用到的关键技术 ...

  6. Spark Streaming 入门

    概述 什么是 Spark Streaming? Spark Streaming is an extension of the core Spark API that enables scalable, ...

  7. Python 爬虫监控女神的QQ空间新的说说,实现秒赞,并发送说说内容到你的邮箱

    这个文章主要是在前一篇文章上新增了说说秒赞的功能 前一篇文章可以了解一下 那么,这次主要功能就是 监控女神的 QQ空间,一旦女神发布新的说说,马上点赞,你的邮箱马上就会收到说说内容,是不是想了解一下 ...

  8. Autofac的AOP面向切面编程研究

    *:first-child { margin-top: 0 !important; } .markdown-body>*:last-child { margin-bottom: 0 !impor ...

  9. 从一道面试题深入了解java虚拟机内存结构

    记得刚大学毕业时,为了应付面试,疯狂的在网上刷JAVA的面试题,很多都靠死记硬背.其中有道面试题,给我的印象非常之深刻,有个大厂的面试官,顺着这道题目,一直往下问,问到java虚拟机的知识,最后把我给 ...

  10. Flask基础(05)-->路由的基本定义

    # 导入Flask from flask import Flask # 创建Flask的应用程序 app = Flask(__name__) # http://127.0.0.1:5000/123或者 ...