Java基础教程:注解
Java基础教程:注解
本篇文章参考的相关资料链接:
- 维基百科:https://zh.wikipedia.org/wiki/Java%E6%B3%A8%E8%A7%A3
- 注解基础与高级应用:http://linbinghe.com/2017/ac8515d0.html
- 秒懂注解:https://blog.csdn.net/briblue/article/details/73824058
概述
这篇文章参考了很多其他文章的写作思路和篇章内容,主要用来帮助我们更好的理解Java中注解的使用,解开注解的神秘面纱。
维基百科上对注解的解释是这样的:
Java注解又称Java标注,是Java语言5.0版本开始支持加入源代码的特殊语法元数据[1]。Java语言中的类、方法、变量、参数和包等都可以被标注。和Javadoc不同,Java标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java虚拟机可以保留标注内容,在运行时可以获取到标注内容[2]。 当然它也支持自定义Java标注[3]。
我们可以这样理解,就是我们在类、方法、变量、参数等元素上面贴一个标签,并且我们能够在运行时动态的获取到这些标签。
我们在方法上贴了一个名为RoleCheck的标签,它里面有一个标签的描述信息为level。在运行该方法时,我们同时可以获取到这个标签及里面的描述信息。具体的语法和更多的内容我们将会在下面的文章中分享到。
内置注解
Java 定义了一套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中
作用在代码的注解是
- @Override - 检查该方法是否是重载方法。如果发现其父类,或者是引用的接口中并没有该方法时,会报编译错误。
- @Deprecated - 标记过时方法。如果使用该方法,会报编译警告。
- @SuppressWarnings - 指示编译器去忽略注解中声明的警告。
作用在其他注解的注解(或者说 元注解)是:
- @Retention - 标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以通过反射访问。
- SOURCE:注解将被编译器丢弃
- CLASS:注解在class文件中可用,但会被JVM丢弃
- RUNTIME:JVM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。
- @Documented - 标记这些注解是否包含在用户文档中。
- @Target - 标记这个注解应该是哪种 Java 成员。
- @Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)
关于Target:
你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。
类比到标签,原本标签是你想张贴到哪个地方就到哪个地方,但是因为 @Target 的存在,它张贴的地方就非常具体了,比如只能张贴到方法上、类上、方法参数上等等。@Target 有下面的取值
- ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
- ElementType.CONSTRUCTOR 可以给构造方法进行注解
- ElementType.FIELD 可以给属性进行注解
- ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
- ElementType.METHOD 可以给方法进行注解
- ElementType.PACKAGE 可以给一个包进行注解
- ElementType.PARAMETER 可以给一个方法内的参数进行注解
- ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
从 Java 7 开始,额外添加了 3 个注解:
- @SafeVarargs - Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告。
- @FunctionalInterface - Java 8 开始支持,标识一个匿名函数或函数式接口。
- @Repeatable - Java 8 开始支持,标识某注解可以在同一个声明上使用多次。
自定义注解
内置注解我们可以直接用到就只有lang中的几个,annotation中几个注解的都是作用在其他注解上的,我们称之为元注解。其他注解就是我们的自定义注解!
定义注解
使用@interface自定义注解,会自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。
在定义注解时,不能继承其他的注解或接口。
@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
public @interface RoleCheck {
int[] level() default 0;
}
比如上面这个代码中,我们定义一个名叫RoleCheck的注解(标签),和一个名为level配置参数(一个标签描述信息,是数值型的),并且默认值为0。
描述注解
但是现在这个注解并不能直接使用,因为我们还没有用元注解去描述这个注解。
1.这个注解在哪里保存呢?
@Retention,当然是RUNTIME:JVM将在运行期间保留注解,因此可以通过反射机制读取注解的信息。
2.这个注解的运用场景是哪里?也就是说它被写在哪里?
@Target,我们选择 ElementType.METHOD ,它可以给方法进行注解。
3.用不用@Document?
@Documented 表示含有该注解类型的元素(带有注释的)会通过javadoc或类似工具进行文档化,Documented是一个标记注解(类似@Override 这种只需要一个简单的声明即可的注解即为标记注解),没有成员。我们这里用或不用都可以,因为我们不涉及文档化处理,但是还是写上了。
最终注解将变成如下的样子:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RoleCheck {
int[] level() default 0;
}
说明:
如果只有一个参数成员,最好把参数名称设为”value”,后加小括号。注解在只有一个元素且该元素的名称是value的情况下,在使用注解的时候可以省略“value=”,直接写需要的值即可。也就是下面这样。
public @interface RoleCheck {
int value() default 0;
}
//用的时候,不用写参数名称了,直接写值
@RoleCheck(1)
public void doSomeThing()
{
.....
}
使用注解
//注解没有属性
@RoleCheck
public void do(){.....} //注解只有一个参数为value的属性
@RoleCheck(1)
public void do(){.....} //注解有一到多个属性
@RoleCheck(level=1,name="MS")
public void do(){.....}
注解处理器
看完以上的内容,我们其实只是做了一件事,就是给不同的物件贴上标签,但是只贴上标签,如果我们不会根据标签进行处理的话,就毫无意义了,和注释毫无区别。
注解处理器就是我们的处理环节,注解处理器可以在运行时通过反射机制读取到标签的信息从而进行处理。
1、首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
2、然后通过 getAnnotation() 方法来获取 Annotation 对象。
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
或者是 getAnnotations() 方法。
public Annotation[] getAnnotations() {}
前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解。
一个实例
我们做的事情是什么,通过class对象的 isAnnotationPresent()判断我Test类是不是有@RoleCheck注解,如果有的话就把这个注解的描述信息打印出来,这里打印出的是默认值。
@RoleCheck
public class Test { public static void main(String[] args) { boolean hasAnnotation = Test.class.isAnnotationPresent(RoleCheck.class); if ( hasAnnotation ) {
RoleCheck testAnnotation = Test.class.getAnnotation(RoleCheck.class);
System.out.println("id:"+roleCheck.level());
}
} }
上面的例子中,只是检阅出了注解在类上的注解,其实属性、方法上的注解照样是可以的。同样还是基于反射。
//返回HelloController类中所有定义的方法
Method[] methods = HelloController.class.getDeclaredMethods();
//遍历每一个方法
for(Method method:methods)
{
//对于标有注解,且名称为doSomething的方法进行处理
RoleCheck roleCheck =method.getAnnotation(RoleCheck.class);
if(roleCheck!=null&&method.getName().equals("doSomething"))
{
//..........
}
}
**********************************************************
//返回HelloController类中所有定义的字段
Field[] fields = HelloController.class.getDeclaredFields();
//遍历每一个字段
for(Field field :fields)
{
RoleCheck roleCheck = field.getAnnotation(RoleCheck.class);
if(roleCheck!=null&&field.getName().equals("level"))
{
//.......
}
}
注解的使用场景
当开发者使用了Annotation 修饰了类、方法、Field 等成员之后,这些 Annotation 不会自己生效,必须由开发者提供相应的代码来提取并处理 Annotation 信息。这些处理提取和处理 Annotation 的代码统称为 APT(Annotation Processing Tool)。我们可以给自己答案了,注解有什么用?给谁用?给 编译器或者 APT 用。
比如举一个注解使用实例,JUNIT测试框架:
public class ExampleUnitTest {
@Test
public void addition_isCorrect() throws Exception {
assertEquals(4, 2 + 2);
}
}
@Test 标记了要进行测试的方法 addition_isCorrect().
再举一个注解使用实例,SpringMVC
@RequestMapping(value = "/add.do")
public String addOrder(Order order) {
try {
orderService.add(order);
return "操作成功";
} catch (Exception e) {
e.printStackTrace();
return "操作失败,请重试";
}
}
@RequestMapping表明了要进行地址映射的方法。
Java基础教程:注解的更多相关文章
- Java基础教程——注解
注解 JDK 5开始,Java支持注解. 注解,Annotation,是一种代码里的特殊标记,这些标记可以在编译.类加载.运行时被读取并执行,而且不改变原有的逻辑. 注解可以用于:生成文档.编译检查. ...
- Java基础教程(18)--继承
一.继承的概念 继承是面向对象中一个非常重要的概念,使用继承可以从逻辑和层次上更好地组织代码,大大提高代码的复用性.在Java中,继承可以使得子类具有父类的属性和方法或者重新定义.追加属性和方法. ...
- Java基础教程:IDEA单元测试
Java基础教程:IDEA单元测试 环境配置 使用idea IDE 进行单元测试,首先需要安装JUnit 插件. 安装JUnit插件步骤 File-->settings-->Plguins ...
- Java基础教程(12)--深入理解类
一.方法的返回值 当我们在程序中调用方法时,虚拟机将会跳转到对应的方法中去执行.当以下几种情况发生时,虚拟机将会回到调用方法的语句并继续向下执行: 执行完方法中所有的语句: 遇到return语句: ...
- Java基础教程:网络编程
Java基础教程:网络编程 基础 Socket与ServerSocket Socket又称"套接字",网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个s ...
- Java基础教程(5)--变量
一.变量 1.变量的定义 正如上一篇教程<Java基础教程(4)--面向对象概念>中介绍的那样,对象将它的状态存在域中.但是你可能仍然有一些疑问,例如:命名一个域的规则和惯例是什么?除 ...
- Java基础教程:Lambda表达式
Java基础教程:Lambda表达式 本文部分内容引用自OneAPM:http://blog.oneapm.com/apm-tech/226.html 引入Lambda Java 是一流的面向对象语言 ...
- Java基础教程:泛型基础
Java基础教程:泛型基础 引入泛型 传统编写的限制: 在Java中一般的类和方法,只能使用具体的类型,要么是基本数据类型,要么是自定义类型.如果要编写可以应用于多种类型的代码,这种刻板的限制就会束缚 ...
- Java基础教程:多线程基础(1)——基础操作
Java:多线程基础(1) 实现多线程的两种方式 1.继承Thread类 public class myThread extends Thread { /** * 继承Thread类,重写RUN方法. ...
随机推荐
- VirtualBox设置NAT端口映射
原文地址 :http://www.2cto.com/os/201209/153863.html VirtualBox设置NAT端口映射 好吧,我知道这个问题有很多人都讲过,但是,你们不觉得VB ...
- 微信移动端(wap)开发调试工具
为帮助开发者更方便.更安全地开发和调试基于微信的网页,微信官方推出了 web 开发者工具.它是一个桌面应用,通过模拟微信客户端的表现,使得开发者可以使用这个工具方便地在 PC 或者 Mac 上进行开发 ...
- vs2010中使用luabind
第一部分:在vs2010中生成luabind静态库和动态库 一.前期准备 1.安装boost 下载boost并解压到 D:\mylua\boost_1_56_0,进入 D:\mylua\boost_1 ...
- 从TCP三次握手说起–浅析TCP协议中的疑难杂症(2)
版权声明:本文由黄日成原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/108 来源:腾云阁 https://www.qclo ...
- jQuery性能优化整理
1.总是从ID选择器开始继承 2.class选择器之前使用tag 3.将jQuery对象缓存起来 4.使用链式操作 5.使用子查询 6.对直接的DOM操作进行限制 7.当需要对dom进行多次操作时,使 ...
- IPMI相关漏洞利用及WEB端默认口令登录漏洞
IPMI相关漏洞 0套件漏洞 使用0套件时,只需要Username,口令任意即可绕过身份鉴别执行指令.而且一般还有一个默认的账户admin或者ADMIN. 备注:IPMI是一套主机远程管理系统,可以远 ...
- Linux显示不了中文
原文:https://www.cnblogs.com/hooly/p/8615384.html 版权所有:归属原文作者!!! 查看当前系统默认采用的字符集: # locale 在RedHat/C ...
- fabric入门
author: headsen chen date: 2018-08-12 23:13:16 1,安装 yum -y install epel-releaseyum -y install fabr ...
- Floyd求最小环并求不同最小环的个数
FZU2090 旅行社的烦恼 Time Limit: 2000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u [Subm ...
- Linux 搭建Nginx并添加配置 SSL 证书
1. 安装准备 1.1 gcc安装 安装 nginx 需要先将官网下载的源码进行编译,编译依赖 gcc 环境,如果没有 gcc 环境,则需要安装: [root@nginx ~]# yum -y i ...