初识注解

前面两节学习了springboot的基本使用,其中大量使用了注解来减少代码量,想必大家都觉得挺奇怪的吧。

所以第三节,稍微停顿一下增删改查的脚步,补补一些基础(๑•̀ㅂ•́) ✧。

对于前端来说,注解这个概念很陌生,如此神秘的力量是如何发挥作用的呢,今天学习一下java中的注解:一种形如@xxx的东东,xxx一般是大写字母开头。

什么是注解

注解Annotation是在java源码中对于类、方法、字段、方法参数的一种特殊注释

  • 是一种注释???

之所以说它是注释,是因为注解本身并不会对代码逻辑造成任何影响,对于如何使用注解去完成对应的功能是工具或者说某些容器的事,从这一点出发,感觉挺像注释的,但是它又是很特殊的

  • 特殊在哪里???

注释不会被编译器处理,直接原样复制忽略掉了,但注解可以被编译器打包进class文件中,所以注解被理解为用作标注的元数据。

注解的分类

一般来说注解分为三类:

  1. 编译器默认使用的注解。
  • 例如我们经常在实体类中见到的各种@Overrider,这个基础注解直译就是覆写。
  • @SuppressWarnings,告诉编译器忽略此处的警告。
  • 特点。通过上面两个小 可以发现,这一类的注解编译器使用而已,对于真实的代码跑起来后并不需要,因此这一类注解的特点就是:不会被编译进class文件,编译后编译器就忽略掉这些代码了。
  1. 底层库处理时需要用到的注解,这类注解会被编译进class文件中,但是距离我们一线开发者很遥远,目前不需要关注。
  2. 程序运行时需要读取并产生副作用的注解,这是我们一线开发者的需要经常使用的注解。

注解有啥用

有了上面的小小的基础后,我们基本可以发现,注解可以在程序运行时告诉编译器,它有一些副作用,能帮助开发者做一些工作,而且写完之后到处使用,开发者仅仅需要打一个标签就行。

定义一个注解

上面我们了解了注解的基本情况,大约有了点认识,接下来看一下java官方的定义,毕竟要整点正规军的东西。 官方使用@interface 来定义一个新的注解,基本格式大约如下:

publice @interface Annotation {String value() default "";// 多个参数...
}

几个小约定

  • 一般来说良好的编码风格需要给注解的不同参数设定一个default默认值(虽然很多 的库也不这么干:-D)
  • 常用的参数最好命名为value

元注解

◔ ‸◔? ❓这还没理解注解,咋还冒出来个元注解呢,因为这个是定义注解的第一步 所谓的元注解就是:能够解释其他注解的注解,这样的注解我们就可以称呼它为meta annotation。我们自定义注解需要用到一些重要的元注解,下面介绍几个元注解:

  1. @Target

这个注解告诉编译器我的代码在哪个位置被使用:

  • 在类或接口中被使用:注解内容为 ElementType.TYPE
  • 在字段中被使用:注解内容为 ElementType.FIELD
  • 在方法中被使用:注解内容为 ElementType.METHOD
  • 在构造方法中被使用:注解内容为 ElementType.CONSTRUCTURE
  • 在方法参数中被使用:注解内容为 ElementType.PARAMETER

一个小 ,假如你要定义一个用在方法上的注解,那么就使用@Target(ElementType.METHOD)

@Target(ElementType.METHOD)
public @interface Annotation {String value() default "";
}

假如你要想定义一个注解用在方法或者字段上的注解,可以使用@Target({ElementType.METHOD, ElementType.FIELD})

@Target({ElementType.METHOD,ElementType.FIELD
})
public @interface Annotation {String value() default "";
}

  1. @Retention 这个元注解极其重要,它定义了注解的生命周期,即自定义的注解在代码的什么阶段被使用。
  • 在编译期:RetentionPolicy.SOURCE
  • 在class文件中:RetentionPolicy.CLASS
  • 在运行期:RetentionPolicy.RUNTIME

当然了,如果你一不小心忘了使用这个元注解,那么默认为CLASS。在我们开发中,我们自定义的注解都是RUNTIME的元注解。

@Retention(RetentionPolicy.RUNTIME)
public @interface Annotation {String value() default "";
}

  1. @Repeatable 这个元注解是说自定义的注解可否被重复使用。一线开发比较少用。
  2. @Inherited 这个元注解是说子类可否继承父类定义的注解,但是它只能对@Target(ElementType.TYPE)类型的注解生效,而且只是针对class

综上所述,自定义注解时,最重要的就是必须设置@Target @Retention,以上一节的mybatis中的基础注解@Select为例:

可以发现它生命周期是在RUNTIME,适用范围在METHOD上,另一个元注解就比较陌生啦。

所以啊o_O,java中注解千千万,以后遇到陌生注解再说,目前够用(〃'▽'〃)……

使用注解

在实战中使用,在模拟中练习是最好的学习方式,本节尝试手写一个自定义注解去体会体会注解的奥妙,不过再开始写BUGS之前,还有一些理论知识需要补充: 上一节注解的定义中解释了@Retentions元注解能够规定注解的三个生命周期,那个这三个生命周期要干啥呢:

  • SOURCE生命周期的注解编译期使用,也就是说我们只关心使用就行。
  • CLASS仅在build之后中的class文件中存在,与我们一线开发关系也不大。
  • RUNTIME是我们经常要使用并且可以充分发挥我们程序员才智的阶段。

一个小小的tips

对于前端来说,下面的知识很陌生(说得好像其他知识你不陌生一样 ): java中build后都是class文件,注解继承自java.lang.annotation.Annotation,至于如何读取注解,需要继续学习反射API,这就是下一节需要补充的知识了,这一节我们假装 会用了。

反射API基本操作

既然我们要读取Annotation,一般有以下几个步骤:

  1. 首先我们要先判断它存不存在。常见的判断的API如下
  • Class.isAnnotationPresent(Class)
  • Field.isAnnotationPresent(Class)
  • Method.isAnnotationPresent(Class)
  • Constructor.isAnnotationPresent(Class)
//判断@Test注解是否存在与Test中
Test.class.isAnnotationPresent(Class)

  1. 存在的话,我们读取注解
  • Class.getAnnotation(Class)
  • Field.getAnnotation(Class)
  • Method.getAnnotation(Class)
  • Constructor.getAnnotation(Class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {String value() default "";
}
//获取定义在Demo类上的@Test注解
Test test = Demo.class.getAnnotation(Test.class)
String value = test.value()
//...

练习自定义注解

有了上述的基础知识之后,我们开始练习一下,手写一个简单的注解,实现判断类中的字段的最大值最小值

  1. 定义一个注解@Range
package com.wushao;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD,ElementType.TYPE
})
public @interface Range {int min() default 0;int max() default 255;
}

  1. 应用在一个类中和类中字段中
package com.wushao;@Range(min = 1)
public class Person {//name这个字符串长度必须在1-20之间@Range(min = 1, max = 20)public String name;//city这个字符串长度最大为10,有个默认最小值0@Range(max = 10)public String city;@Range(min = 1, max = 10)public int age;@Overridepublic String toString() {return "Person{" +"name='" + name + ''' +", city='" + city + ''' +", age=" + age +'}';}public Person(String name, String city, int age) {this.name = name;this.city = city;this.age = age;}}

  1. Main入口函数中简单的测试
package com.wushao;import java.lang.reflect.Field;public class Main {public static void main(String[] args) {Person p1 = new Person("wushao", "Qingdao", 20);Person p2 = new Person("", "Shanghai", 0);Person p3 = new Person("gaoyuayuan", "Beijing", 199);Range range = Person.class.getAnnotation(Range.class);System.out.println("Person的注解:" + range);range.max();for (Person p : new Person[] {p1, p2, p3}) {try {check(p);System.out.println("Person " + p + " checked ok.");} catch (IllegalArgumentException | ReflectiveOperationException e) {System.out.println("Person " + p + " checked failed: " + e);}}}// 类中其他方法必须使用static关键字修饰,并且抛出以下两个错误static void check(Person person) throws IllegalArgumentException, ReflectiveOperationException {       //遍历person类中的所有字段for (Field field: person.getClass().getFields()) {//获取定义在Field中的注解`@Range`Range range = field.getAnnotation(Range.class);//如果存在这个注解进行操作if (range != null) {//获取不同Field字段的值Object value = field.get(person);//TODO: 核心判断逻辑}}}
}

上面的TODO中的校验函数是挺重要的

static void check(Person person) throws IllegalArgumentException, ReflectiveOperationException {for (Field field: person.getClass().getFields()) {Range range = field.getAnnotation(Range.class);if (range != null) {Object value = field.get(person);// 判断字段值是否是String类型的if (value instanceof  String) {String s = (String) value;System.out.println("s: "+ s);//如果字段的值不符合注解的最大最小值抛出一个异常,会被`Main`函数的catch if (s.length() < range.min() || s.length() > range.max()) {throw new IllegalArgumentException("Invalid field is: " + field.getName());}}}}}

简单的执行一下,上面的demo实例发现打印如下:

发现在检验到p2这个人的时候,报错了,因为他的name为空,长度不满足注解要求的1-20之间。

学习过程中感谢廖雪峰和菜鸟教程

接下来继续填坑,学习反射是如何读取上面的注解的↖(^ω^)↗

@retention注解作用_前端初学SpringBoot系列(三)自定义注解的学习与练习相关推荐

  1. springboot项目中自定义注解的使用总结、java自定义注解实战(常用注解DEMO)

    初学spring的时候使用注解总觉得使用注解很神奇,加一个注解就能实现想要的功能,很好奇,也想自己根据需要写一些自己实现的自定义注解.问题来了,自定义注解到底是什么?肯定会有人和我一样有这个疑惑,我根 ...

  2. 【j360-boot】Spring-boot系列三(崩溃模式,不是你崩就是电脑崩)

    2019独角兽企业重金招聘Python工程师标准>>> j360-boot spring-boot入门工程之j360-boot:(欢迎star.fork) https://githu ...

  3. @retention注解作用_分分钟带你玩转SpringBoot自定义注解

    在工作中,我们有时候需要将一些公共的功能封装,比如操作日志的存储,防重复提交等等.这些功能有些接口会用到,为了便于其他接口和方法的使用,做成自定义注解,侵入性更低一点.别人用的话直接注解就好.下面就来 ...

  4. @enableautoconfiguration注解作用_如何让代码变“高级”-Spring组合注解提升代码维度(这么有趣)...

    [如何让代码变"高级"]-Spring组合注解提升代码维度 "致"高级"工程师(BUG工程师) 一颗折腾的心:heartpulse: 原创不易,点个赞 ...

  5. SpringBoot系列三:SpringBoot基本概念(统一父 pom 管理、SpringBoot 代码测试、启动注解分析、配置访问路径、使用内置对象、项目打包发布)...

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.了解SpringBoot的基本概念 2.具体内容 在之前所建立的 SpringBoot 项目只是根据官方文档实现的一个基础程 ...

  6. SpringBoot 2.x 自定义注解annotation实现MicroMeter埋点

    介绍 Micrometer 为 Java 平台上的性能数据收集提供了一个通用的 API,应用程序只需要使用 Micrometer 的通用 API 来收集性能指标即可.Micrometer 会负责完成与 ...

  7. 【SpringBoot】通过自定义注解对BigDecimal输出的小数位数进行格式化

    文章目录 前言 一.JsonSerializer 二.ContextualSerializer 三.实现 1.继承JsonSerializer类,实现ContextualSerializer接口 2. ...

  8. SpringBoot整合AOP + 自定义注解实现简单的权限验证

    1.简介 主要通过自定义注解,使用SpringAOP的环绕通知拦截请求,判断该方法是否有自定义注解,然后判断该用户是否有该权限,这里做的比较简单. 2.项目搭建 这里是基于SpringBoot的,对于 ...

  9. SpringBoot中利用自定义注解优雅地实现隐私数据脱敏(加密显示)

    前言 这两天在整改等保测出的问题,里面有一个"用户信息泄露"的风险项(就是后台系统里用户的一些隐私数据直接明文显示了),其实指的就是要做数据脱敏. 数据脱敏:把系统里的一些敏感数据 ...

  10. c++和java哪个难_前端和Java开发哪个难?哪个学习容易一点?

    首先我说一下Java和web两者的区别: Java是一门面向对象编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征. ...

最新文章

  1. PHP自动加载类—__autoload()和spl_autoload_register()
  2. pocoserver无限重启_poco相机老版本
  3. IT-标准化(中国)有限公司-网络拓朴图
  4. devc++鼠标变成了光标_游戏鼠标到底能不能提升你的实力?
  5. linux下遍历目录树方法总结,linux下遍历目录树方法总结(下)
  6. 逻辑综合——优化电路
  7. MySQL故障检测_mysql主从故障检测处理脚本
  8. Bootstrap3 模态对话框的调用方式
  9. 【hortonworks/registry】创建嵌套结构的scheam和带空值的schema
  10. c mysql命令_最基本的mysql命令
  11. mysql配置所有ip连接_Mysql查看用户连接数配置及每个IP的请求情况
  12. 东方乐器及音乐、音乐的常识
  13. linux学习之vi编辑器的使用详解
  14. 最新delphi7序列号和破解文件
  15. 都有哪些查找和下载英文文献的方法?
  16. 2020,2022年全年详细工作日、周末、节假日数据表sql
  17. AJAX技术学院风连衣裙,学院风连衣裙怎么搭配好看
  18. win10升级win11操作
  19. 鼠标滑过显示红色禁用符号
  20. 举个栗子!Tableau 技巧(139):突出显示文本表的行或列

热门文章

  1. 阶段2 JavaWeb+黑马旅游网_15-Maven基础_第3节 maven标准目录结构和常用命令_07maven常用命令...
  2. [luogu1486][NOI2004]郁闷的出纳员
  3. 编程之美学习之最长子序列的解法
  4. 局域网访问PHP项目网站 用IP地址进入
  5. oracle的loop等循环语句的几个用法小例子[转]
  6. nginx反向代理docker registry报”blob upload unknown解决办法
  7. 微信运营:必须收藏的101条万能微信标题公式
  8. 【IPC通信】基于管道的popen和pclose函数
  9. Effective C++读书笔记05
  10. Windows Server 2003 SP2 中文版下载