文章目录

  • 前言
  • 复习注解
    • 元注解
      • @Retention 存活时间
      • @Documented 文档
      • @Target 目标
      • @Inherited 继承
      • @Repeatable 可重复
    • 注解属性
  • 注解实现-反射
    • 反射获取注解方法
    • 注解的使用场景
    • 后续
    • 导航

前言

这两天在gitHub上看一个开源项目,发现项目中有许多自定义注解。虽然在学JavaSE的时候学个注解,但是主要讲的是如何自定义注解,和一些元注解的知识点。并没有涉及到注解如何实现具体的功能。直到看到这个项目,突然醍醐灌顶。
由于篇幅过长,分成两篇来写。

复习注解

注解是在Java 1.5 的时候被引入的,注解的创建与接口十分相似。就是在interface关键字前面加一个@符号。

public @interface MyAnnotation{}

创建玩注解之后就可以在想要添加主机的地方使用了,但是想要让注解能够正常工作,还需要给它化化妆。什么是化妆那,这里就要引入元注解的一个概念了,元注解他也是一个注解,只不过它是用来修饰注解的注解。有点迷?不慌咱慢慢看。

元注解

元注解一共有五种分别为:

  • @Retention
  • @Documented
  • @Target
  • @Inherited
  • @Repeatable
    他们的使用方法就是在创建注解的时候在,所要创建的注解上使用他们:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
... ...
public @interface MyAnnotation{}

@Retention 存活时间

Retention中文意思是保留的意思。当@Retention应用到一个注解上的时候 ,通过参数可以设置这个注解的存活时间。什么是存活时间,就是说通过不同参数可以确定@Retention修饰的注解在那种情况下会消失,是保留到源码阶段、还是编译阶段、还是加载到JVM那。

下面看一下它的参数:

  • RetentionPolicy.SOURCE

注解只被保留到编译阶段,当编译器编译到它的时候看到参数为 RetentionPolicy.SOURCE会直接将其从源码中剔除。

  • RetentionPolicy.SOURCE

注解制备保留到编译进行的时候,也就是能保证在编译期间注解也存在,但是不能进入JVM中。

  • RetentionPolicy.SOURCE

注解可以保留到程序中,它会被加载到JVM中从而在服务中起作用。

@Documented 文档

这个注解,翻译过来就是文档。那他并没有其他功能上的作用,主要作用就是能讲注解中的元素包含到Javadoc中去。

@Target 目标

Target 有目标的意思,他的意思就是说,这个注解能够使用的地方是哪里,是方法上、类上还是参数上。我们通过它的参数就可以进行设置。

参数 作用
ElementType.ANNOTATION_TYPE 可以使用在注解上
ElementType.CONSTRUCTOR 可以在构造方法上使用
ElementType.FIELD 可以在属性上使用注解
ElementType.LOCAL_VARIABLE 作用在局部变量上
ElementType.METHOD 作用在方法上
ElementType.PACKAGE 作用在包上
ElementType.PARAMETER 作用在方法内的参数上
ElementType.TYPE 可以给类型进行注解,比如类、接口、枚举

@Inherited 继承

Inherited 意思为继承,这个元注解的作用有点绕。就是说如果@Inherited注解作用与自定义注解@MyAnnotation上,然后在A类上使用了自定义注解,然后A类的子类,就相当于也拥有@MyAnnotation注解。

/*自定义注解*/
@Inherited
public @interface MyAnnotation{}
---------------------------
/*A类*/
@MyAnnotation
public class A{}/*B类继承A类*/
public class B extent A{}/*
//此时,B类也继承了A类的注解。相当于
@MyAnnotation
public class B extent A{
}
*/

@Repeatable 可重复

这个注解是在Java 1.8的时候加进来的。那可重复是什么意思那,就是说使用注解的时候可以同时使用多次注解。

public class A{@MyAnnotation("教师")
@MyAnnotation("公务员")public void test(){}}

如果想实现这样的效果,那么就需要使用@Repeatable注解修饰@MyAnnotation注解。@MyAnnotation才可以在一个方法或其它地方使用多次。

注解属性

注解的属性其实就好像实体类里面的属性,只是写法上有稍微的不同。但是注解是没有方法的,

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
... ...
public @interface MyAnnotation{int id();
String value();
}

注意这里id()value()表示的不是方法而是属性也可叫做注解的变量。
注解的赋值方法就是在使用注解的时候,通过注解中的对应属性="xxx"的形式

@MyAnnotation(id=101,value="Hello Annotation")
public void test(){}

注解属性可以设置默认值,也就是如果使用注解时没有赋予特定的值,就使用默认值。

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
... ...
public @interface MyAnnotation{int id() default 101;
String value();
}

这里还有一个注意点,如果注解中只有一个名字为value的属性的时候,应用这个注解的时候可以直接填写属性值。


pulic @interface MyAnnotation{String value;
}
@MyAnnotation("Hi")
public void test(){}

如果定义的这个注解中没有属性值,我们在使用注解的时候就不用在写括号了

@MyAnnotation
public void test(){
}

注解实现-反射

注解的知识经过上面的内容,应该能够有个了解。那么我们定义好后注解,也是用了,但是并没有什么实质的效果。哪有人该说了那定义有什么用?其实不然,如果真的没有用那么Java官方就不会定义注解了。

好下面我们就给自定义的注解注入灵魂,实现当使用注解后完成相应的功能。那该如何实现那,注解中又不能写方法,之有属性值, 我们也不能通过new获取注解。这里就要提到一个比较重要的知识点就是反射

我们可以通过反射获取作用在类或者方法上的注解让,后进行对应的处理。

反射获取注解方法

注解通过反射获取。首先通过class对象的isAnnotationPresent()方法判断他是否应用了某注解。

public Boolean isAnnotationPresent(Class<? extent Annotation> annotationClass) {}

然后通过getAnnotation()方法来获取Annotation对象。

public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}

或者是getAnnotations()方法

public Annotation[] getAnnotations(){}

前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解。
如果获取到的Annotation如果不为null,则就可以调用他们的属性方法了。比如

@MyAnnotation()
public class Test{public static void main(String[] agrs){boolean hasAnnotation = Test.class.isAnnotationPressent(TestAnnotation.class);if(hasAnnotation){TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class);System.out.println('id:'+testAnnotation.id());}}
}

运行结果:

id:101

上面是获取类上的注解,其实方法、属性的注解都是可以通过反射进行获取的。
自定注解:

package com.zhao.annotationaop.annotation;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.METHOD)
public @interface MyAnnotation {String value() default "Hello Annotation";
}

编写测试类

public class TestAnnotation {@MyAnnotation("Hi")public void testMethod(){System.out.println("fun");}public static void main(String[] args) throws  NoSuchMethodException {Class<TestAnnotation> aClass = TestAnnotation.class;Method msg = aClass.getDeclaredMethod("testMethod");msg.setAccessible(true);MyAnnotation annotation = msg.getAnnotation(MyAnnotation.class);System.out.println(annotation.value());}
}

运行结果

Hi

这里需要注意一下,如果想要注解在运行时能够获取到,那么必须加上@Retention(RetentionPolicy.RUNTIME)这个注解参数,因为这个参数是指,注解能在jvm中被执行。

注解的使用场景

到这里应该大家对注解都有一定的了解了,但是还是可能会有疑惑注解到底有什么用呐。
我们不妨先看看官方的回答:

注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响。
注解有许多用处,主要如下:

  • 提供信息给编译器: 编译器可以利用注解来探测错误和警告信息
  • 编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。
  • 运行时的处理: 某些注解可以在程序运行的时候接受代码的提取
    值得注意的是,注解不是代码本身的一部分。

从官方的话我们可以看出注解的作用并不是来写主要业务的,而是通过注解实现一些对代码的处理。

如果大家用过LomBok在实体类上面加一个@Data就可以帮助我们生成实体类的get和set的方法,在或者说Swagger生成接口文档,在对应的接口上加上对应的注解就可以实现生成对应的接口文档。注解只是起到到了标签的作用,具体的实现方式是有对应的程序获取到注解这个标识,然后去处理产生的。

那么我们可以用注解做什么呢?

现在我们就动手写一个自己的注解,通过这个注解来检测程序是否报错。这是一个简单的小案例。

首先写一个注解@Jiance

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Jiance {}

要测试的程序Cheshi并在方法上加上注解

public class Cheshi {@Jiancepublic void suanShu(){System.out.println("1234567890");}@Jiancepublic void jiafa(){System.out.println("1+1="+1+1);}@Jiancepublic void jiefa(){System.out.println("1-1="+(1-1));}@Jiancepublic void chengfa(){System.out.println("3 x 5="+ 3*5);}@Jiancepublic void chufa(){System.out.println("6 / 0="+ 6 / 0);}public void ziwojieshao(){System.out.println("我写的程序没有 bug!");}
}

运行检测程序TestJiance

public class TestJiance {public static void main(String[] args) {Cheshi cheshi = new Cheshi();Class<Cheshi> cheshiClass = Cheshi.class;Method[] declaredMethods = cheshiClass.getDeclaredMethods();StringBuilder log = new StringBuilder();log.append("**************日志****************\n");int num = 0;for (Method declaredMethod : declaredMethods) {Jiance annotation = declaredMethod.getAnnotation(Jiance.class);if (annotation!=null){try {declaredMethod.setAccessible(true);declaredMethod.invoke(cheshi,null);} catch (Exception e) {num++;log.append(declaredMethod.getName()+":error:"+e.getCause().getMessage()+"\n");}}}log.append("cheshi has "+num+ " error");System.out.println(log);}
}

执行结果:

1+1=11
1234567890
1-1=0
3 x 5=15
**************日志****************
chufa:error:/ by zero
cheshi has 1 error

这样我们就成了这小的案例。我们通过我们自定义的注解,来检测所有cheshi类中有错的方法。
注解的作用主要取决于你想用它做什么。

后续

利用反射获取注解并实现功能通过上面已经实现了,但是还有一种方式也可以获取注解,并实现对应的功能逻辑。
那就是利用Spring框架的Aop来实现,AOP面向切面编程,我们可以利用AOP做很多事情。那如果AOP遇到注解会发生什么那。
下一篇我们利用自定义注解和Aop实现接口防刷的功能。也就是在一段时间内如果大量访问接口,就会触发保护的一个案例。

End!!! 如有疑问请留言评论!

导航


接口防刷案例【传送门】

啊啊,终于搞明白了,原来注解是这么一回事。6000+字理解注解【一】相关推荐

  1. php image gallery in metro ui,终于搞明白糟糕的METRO UI是怎么回事了

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 METRO的意思是地铁,微软决策层犯SB请了一些更SB的设计师以美国地铁标识牌的设计为"灵感"而创造的糟糕界面. 界面尽量以文字为主 ...

  2. 终于搞明白gluPerspective和gluLookAt的关系了

    2019独角兽企业重金招聘Python工程师标准>>> 终于搞明白gluPerspective和gluLookAt的关系了 函数原型 gluLookAt(GLdoble eyex,G ...

  3. matlab中异步电机y接法,电机接法Y和三角形什么区别,今天终于搞明白了!

    原标题:电机接法Y和三角形什么区别,今天终于搞明白了! 电动机三角形接法和星形接法区别: 1.异步电动机因其结构简单.价格便宜.可靠性高等优点被广泛应用.但在起动过程中起动电流较大,所以容量大的电动机 ...

  4. python和c混合编程 gil_终于搞明白python与gil

    感想:东看一篇文章西看一篇文章,终于把gil的概念理顺了 我们都知道,比方我有一个4核的CPU,那么这样一来,在单位时间内每个核只能跑一个线程,然后时间片轮转切换.但是Python不一样,它不管你有几 ...

  5. java的向下转型_终于搞明白向下转型的作用了,还不懂的进来看下.

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 之前一直搞不明白,向下转型的实际意义,虽然知道向下转型怎么写, 现在我来讲解下 向下转型 的实际作用,如果有错的话,大家可以指出, 如果认为我说的对的话可 ...

  6. 感染新冠后为啥会丧失​嗅觉?最新《细胞》论文终于搞明白了!

    感染新冠后,患者的一大症状就是会丧失嗅觉,然而这一症状背后的机理却始终没有得到阐明.日前,顶尖学术期刊<细胞>上的一篇论文,终于揭开了背后的谜底--原来新冠病毒会让嗅觉受体出现下调,使得人 ...

  7. 最详细的解释小白也能听懂,终于搞明白了

    前言 2021春季社招正在火热招聘当中,很多人都挂在了技术知识掌握还是不够广,不够深,甚至连一些基础的问题都只能模模糊糊的回答出来.你说,这跳槽不是跳了个寂寞吗? 其实,根本原因还是对于自己的技术栈掌 ...

  8. 真香定律!阿里、字节跳动、京东、腾讯、小米等名企高频面试,终于搞明白了

    前言 说真的,在 Java 使用最多的集合类中,List 绝对占有一席之地的,它和 Map 一样适用于很多场景,非常方便我们的日常开发,毕竟存储一个列表的需求随处可见.尽管如此,还是有很多同学没有弄明 ...

  9. html调用eps,EPS/改性EPS/石墨EPS:终于搞明白了

    在现代外墙保温装饰工程上经常会爆出EPS,XPS,改性EPS啊-- 这些高科技范儿的词语,对于很多用户或者外行经常搞的头晕脑胀,今天DPX君就为大家讲解一下.一 什么是聚苯板(EPS) 聚苯板全称聚苯 ...

最新文章

  1. 数据结构与算法分析c++第四版_研分享 | 人工智能学院数据结构与算法分析考研备考整理...
  2. 零基础python必背代码-30个Python常用极简代码,拿走就用
  3. 用仿ActionScript的语法来编写html5——终篇,LegendForHtml5Programming1.0开源库件
  4. 18135usm_佳能PZ-E1+EF-S 18-135mm f/3.5-5.6 IS USM镜头 小型工作室的利器
  5. ecshop 手机端没做和电脑一样显示
  6. Android Camera (13)---MTK平台相机插值修改
  7. centos5.2 lamp安装指南
  8. 在网页中嵌入百度地图的步骤
  9. 7.docker pull
  10. PHP正则获取HTML里需要的数据
  11. mongodb详细优化策略方案
  12. MOS管自举电路工作原理以及升压自举电路结构图分析
  13. phpStudy点击phpadmin出404窗口的解决办法
  14. linux下Ftp客户端程序与Makefile
  15. (转)eclipse 打开pom.xml文件很慢 设置pom.xml打开方式
  16. Android 自定义注解处理器
  17. 叶新伟 php,基于php+mysql技术bbs论坛设计的开发与实现最终版(样例3)
  18. 永中软件自己越描越黑
  19. 用户存续期价值评估CLV(三) Gamma-Gamma模型 Python模拟
  20. 微信小程序-从注册到上架

热门文章

  1. 就在明天丨数据中心边缘计算分论坛
  2. ERP系统-应收应付子系统-应收/应付账单
  3. Android内存原理
  4. OSD的主要实现方法和类型
  5. symfonos: 1
  6. python自动化(四)app自动化:2.Android Studio
  7. web前端-综合应用案例-简历表页面的制作-educoder
  8. C++:最小化多个变量的标量函数 使用Nelder-Mead算法(附完整源码)
  9. 倘若生活没有改变,期盼又从何而来
  10. 基于AI恶意软件分类技术(5)