这篇文章我们来讲一下Java中的注解
其实这部分内容算是Javaweb的补充内容,其中还包括Junit测试和反射的相关内容。 Junit测试是一个比较简单的内容,这里就不写了;而反射的相关内容可以看java基础专栏,那里面有详细的叙述。
目录
1.注解概述
2.jdk里面已经定义的注解
2.1 @Override注解
2.2 @Deprecated注解
2.3 @SuppressWarnings(参数)
3.自定义注解
4.在程序中解析注解
5.具体案例
1.注解概述
首先,我们来对注解进行一个全面的认识
注解概念:用来说明程序的,是给计算机看的
格式:@+注解名称
解释:我们知道java里面有注释,注释的概念是:用文字描述程序,给程序员看的;我们类比注释,就给出了注解的概念。唯一不同的是注解是给计算机看的
注解的分类:
- 编译检查:通过代码里面标识的注解,让编译器可以实现基本的编译检查,例@Override
- 编写文档:通过代码里面标识的注解,来生成文档(生成doc文档,也就是api文档,生成类的文档的命令:javadoc 类名)
- 代码分析:通过代码里标识的注解,对代码进行分析(使用反射)
说明:编译检查,很简单,就是程序在编译的时候对代码进行检查,看看它是否符合语法格式,典型的就是对方法的重写时用的注解@Override;编写文档,也很容易理解,就是我们给程序加上注解,然后如果我们要生成api文档,那么就会生成加了注解的部分;代码分析这里先不阐述
关于注解我们要学习的内容:
- jdk里面定义的注解
- 自定义注解
- 在程序中使用(解析)注解
2.jdk里面已经定义的注解
首先,我们先来了解一下jdk里面已经定义了的注解。主要了解以下三个:
- @Override 检测被标记的方法是否是基础父类(接口)的
- @Deprecated 该注解标识的内容表示已过时
- @SuppressWarnings(参数) 用来压制警告的,其中的参数一般传递all,表示压制所有警告
2.1 @Override注解
这个注解就不过多赘述了,我们已经用了很多次了
直接看一下代码吧
很简单,不多讲
2.2 @Deprecated注解
这个注解是用来表示标识的内容已经过时了
注意:是可以用,但是已经过时了。就比如一个程序有了一个新功能,旧的功能过时了,所以我们要对旧的功能进行表示,但是因为还有人会用旧的功能,所以旧的功能还是可以用的
看下代码:
第16行的注解表示方法show1()过时了,所以在第28行输入的时候,idea显示的show1()上面划了条横线,但是注意,show1()方法还是可以用的
2.3 @SuppressWarnings(参数)
@SuppressWarnings(参数)注解是用来压制警告的
具体的看一下代码:
这些标黄的位置就是警告,不是错误,不影响程序运行
然后我们加上注解看一下:
如图所示,警告就没有了
里面的参数我们一般传入的是all,表示压制所有的警告
对于这个注解,我们一般是直接标识在类上的,这样就可以压制整个类的警告了
如图所示,我们这整个类都没有警告了
3.自定义注解
下面,我们来尝试一下自定义注解
我们来看一下java中注解的格式:
它大体上是分两部分组成的。第一部分:元注解,就是49和50两行;第二部分:注解定义,就是第51行
所以注解格式如下:
元注解
public @interface MyAnno {
}
我们仿照它也来定义一个注解:
这里再说明一点内容,我们定义了一个注解,然后进行编译,然后在用javap命令反编译,就能看到注解的本质
注解的本质:注解本质上是一个接口,该接口默认继承Annotation接口
接口反编译出来的内容:public interface MyAnno extends java.lang.annotation.Annotation{}
所以说,注解本质上是一个接口,接口里面能写的内容(常量、抽象方法)注解里面都可以写
但是有所要求:
- 属性的返回值类型,只能包括:基本数据类型、String、枚举、注解、以上类型的数组,只能包括这五大类
- 定义了属性,在使用时要给属性赋值,赋值格式为 属性名=值;还可以使用default关键字给属性赋默认值
- 如果只有一个属性需要赋值,并且属性名为value,那么可以直接写值,不用写value
下面来看一个自定义的注解:
这是自定义的注解,里面写了内容
下面看一下这个注解的使用:
很简单key-value的形式
下面再来讲一下元注解:
元注解:用于描述注解的注解,是jdk已经定义好的
需要掌握的元注解:
- @Target:用于描述注解能够作用的位置,三个取值:TYPE:只作用于类上;METHOD:只作用于方法上;FIELD:只作用与成员变量上
- @Retention:描述注解被保留的阶段 @Retention(RetentionPolicy.RUNTIME),表示当前被描述的注解会保留到class字节码文件中,并被jvm读取到;我们自己写的注解一般是选RUNTIME
- @Document:描述注解是否被抽取到api文档中
- @Inherited:描述被该注解描述的注解注释的类的子类会自动继承这个注解
下面来看一下具体的实例:
我们写自定义的注解时,一般只用前两个注解,后面两个一般不用
注解的定义就是这么多的内容
4.在程序中解析注解
下面我们通过具体的实例来看下注解的在程序中的解析
如图所示,这是我们自定义的一个注解
这个是我们在程序中使用我们自定义的注解
这个就是运行的结果
我们在程序中解析注解,实质上就是在程序中获取注解里面的内容,它包含以下三部分:
- 获取注解定义的位置的字节码文件
- 获取指定的注解
- 调用注解中的抽象方法来获取配置的属性值
这在上面的程序中也是对应上的,运行方法啥的运用的是反射的技术
5.具体案例
情景:你写了一个计算器,能够进行四则运行,现在要求你写一个测试框架,来测试你的计算器是否可以正确运算,如果有错,请返回文件指出错误
代码如下:
这是计算器类
这是我们写的注解
这是我们的测试框架
这是运行结果
最后,我们小结一下
我们以后是要会使用注解,而不是自定义注解来使用。注解给谁用?注解给计算机用,给解析程序用(这个解析程序就是类似于我们的TestCheck类),注解是给这二者用的。并且注解不是我们程序的一部分,可以将注解理解为一个标签,它不是程序的一部分。