一、什么是注解
在 jdk5.0 之后的版本,java 引入了注解。注解让程序员可以直接编写元数据,元数据即描述数据的数据,换句话说,注解是代码的元数据,它修饰、并描述了 java 代码,包括包、类、方法、变量、参数等。
二、注解的作用
1、生成文档。这是最常见的,也是 Java 最早提供的注解。常用的有 @see@param @return 等。
2、跟踪代码依赖性,实现替代配置文件功能。比较常见的是 spring 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。以后 java 的程序开发,最多的也将实现注解配置,具有很大用处。
3、在编译时进行格式检查。如 @override 放在方法前,如果你这个方法并不是覆盖了父类方法,则编译时就能检查出。
4、代码生成。注解可以使用代码中展现的元数据信息来自动生成代码或者 XML 文件,一个不错的例子是 JAXB。 三、注解分类 3.1Java 自带的普通注解
@Override表明当前方法是覆盖了父类方法
- abstract class Fruit {
- protected void showOnTheDesk() {...
- }
- }
- class Apple implements Fruit {@Override public void showInTheDesk() { //编译报错,父类是On不是In ... } }
@Deprecated:说明被标记的元素不推荐使用。这个注解会让编译器产生警告消息。可以使用到方法,类和域上。
@SuppressWarnings
- @Deprecatedpublic void badMethod() { //已经不推荐使用的方法...}
关闭不当的编译器警告信息。
- @SuppressWarnings("unused") private String myNotUsedMethod() { // 因为该私有方法未使用编译器产生了告警信息,使用@SuppressWarnings关闭警告 ...}
3.2 元注解
注解的注解,即是元注解。
普通注解来修饰 java 代码,而元注解用来修饰普通注解,换句话说,可以用元注解来自定义注解。
Java 提供的最主要的元注解有 4 个:@Retention @Target @Documented @Inherited 3.2.1
@Documented@Documented 修饰的注解会自动生成到 javadoc 中
- @Documented@interface Column {
- int id()
- default - 1;
- }
3.2.2
@Inherited@Inherited 修饰的注解类似于继承一样,但并非真的继承,只可以让子类对象使用反射中的 getAnnotations()接口获取父类被 @Inherited 修饰的注解。
- @Inherited@Retention(RetentionPolicy.RUNTIME) public@interface WithInherAnno {}@Retention(RetentionPolicy.RUNTIME)@interface NoInherAnno {}@WithInherAnnopublic static class Father1 {}
- public static class Son1 extends Father1 {}@NoInherAnnopublic static class Father2 {}
- public static class Son2 extends Father2 {}
- public static void main(String[] args) {
- System.out.println(Arrays.toString(new Son1().getClass().getAnnotations()));
- System.out.println(Arrays.toString(new Son2().getClass().getAnnotations()));
- }
输出:
[@WithInherAnno()]
[]
3.2.3
@Retention@Retention 定义了注解的生命周期,即该注解被保留时间的长短。
某些注解仅出现在源码中,被编译器丢弃;
某些注解被编译在 class 文件中,加载到 JVM 中被忽略;
还有的注解被加载到 JVM 中,在 Runtime 期间可用(请注意并不影响 class 的执行,因为 Annotation 与 class 在使用上是分离的)。
@Retention 的原始定义如下:
- public@interface Retention {
- RetentionPolicy value();
- }
@Retention 的取值是 RetentionPolicy 类型,包括如下 3 种情况:
(1)SOURCE: 注解只保留在源文件,当 Java 文件编译成 class 文件的时候,注解被遗弃。
(2)CLASS: 注解被保留到 class 文件,jvm 加载 class 文件时候被遗弃。
(3)
RUNTIME: 注解不仅被保存到 class 文件中,jvm 加载 class 文件之后,仍然存在,保存到 class 对象中,可以通过反射来获取。
- @Retention(RetentionPolicy.RUNTIME)public @interface SelfAnno {}
3.2.4
@Target@Target 定义了该注解要修饰的目标,即该注解所修饰的代码范围。
注解可被用来修饰 package、类、接口、enum、注解类型、方法、构造函数、成员变量、函数参数和局部变量(如循环变量、catch 参数)等。在 Annotation 类型的声明中使用了 target 可更加明晰其修饰的目标。
@Target 原始定义如下:
- public@interface Target {
- ElementType[] value();
- }
@Target 取值是 ElementType[] 数组,可取如下值:
(1)
TYPE: 指的是在类,接口(包括注解)或者 enum 上使用的注解。
(2)
FIELD: 指的在 field 属性,也包括 enum 常量使用的注解。
(3)
METHOD: 指的是在方法声明上使用的注解。
(4)
PARAMETER: 指的是在参数上使用的注解,
(5)
CONSTRUCTOR: 指的是在构造器使用的注解。
(6)
LOCAL_VARIABLE: 指的是在局部变量上使用的注解。
(7)
ANNOTATION_TYPE: 指的是在注解上使用的元注解
(8)
PACKAGE: 指的是在包上使用的注解。3.3 自定义注解
1)使用 @interface 来声明一个注解。
2)自定义的注解,自动继承自 java.lang.annotation.Annotation 接口,不能继承其他的接口。
3)注解包含注解参数,每一个注解参数在自定义注解时以方法的形式来声明,方法名就是参数名,返回值类型就是参数的类型(只能是基本类型、Class、String、enum)。
4)可使用 default 关键字来声明注解参数的默认值。
5)若自定义的注解只包含一个参数,建议把参数名设为 "value"。
6)使用注解修饰代码时,其参数赋值通过 @AnnoName(arg1=value1, arg2=value2…) 的形式。
自定义注解的格式如下:
- @interface注解名 {注解参数1声明;注解参数2声明;……
- }
下面以 @Target 源码为例:
- @Retention(value = RetentionPolicy.RUNTIME)@Target(value = {
- ElementType.ANNOTATION_TYPE
- }) public@interface Target {
- ElementType[] value();
- }
分析如下:
1、用 @Retention 修饰,其参数 value 的值为 RetentionPolicy.RUNTIME。
2、用 @Target 修饰,其参数 value 是个数组,用 {} 形式赋值,值为 ElementType.ANNOTATION_TYPE。
3、定义的 Target 注解,其注解参数名为 value,类型为 ElementType[]。
注:若注解的参数名是 value,在使用该注解修饰代码时可以简写。如果参数类型为数组,但是只赋值一个元素,也可以简写。如上面的简写形式为:
- @Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)
注解参数带默认值的自定义注解举例如下:
- @Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME) public@interface PeopleAge {
- int value()
- default 0;
- }
四、Java 注解的图例小结
五、使用注解的类库 Junit
这个框架用于完成 Java 中的单元测试。自 JUnit4 开始,注解被广泛应用,成为 Junit 设计的主干之一。
基本上,JUnit 处理程序通过反射读取类和测试套件,按照在方法上,类上的注解顺序地执行它们。当然还有一些用来修改测试执行的注解。其它注解都用来执行测试,阻止执行,改变执行顺序等等。
@Test:这个注解向 JUnit 说明这个被注解的方法是一个可执行的测试方法。这个注解只能修饰方法,并且被 JVM 保留至运行时。
- @Testpublic void test(){}
@Before:这个注解用来向 JUnit 说明被修饰的方法应该在所有测试方法之前被执行,常用于测试执行之前初始化,同样只修饰方法。
- @ Beforepublic void init(){}
@After:这个注解用来向 JUnit 说明被注解的方法应该在所有单元测试之后执行,通常用来释放资源,或做一些清理、重置工作。
- @Afterpublic void destroy(){}
Hibernate ORM
Hibernate 是一个使用广泛的对象关系模型(ORM)映射类库,它提供了对象模型和关系型数据库的映射框架,使用注解作为设计的一部分。
- @Entity@Table( name = "hibernate_annotated" )public class HibernateAnnotated{@Id@GeneratedValue@Column( name = "id" )private int id;@Column( name = "description" )private String description;}
上述代码将被注解的 "HibernateAnnotated" 类与数据库中的表 "hibernate_annotated" 映射对应,且主键为 "id",还有一列 "description"。
Spring
Spring 是使用广泛的 Java 企业级应用框架,其一项重要的特性就是在 Java 程序使用依赖注入。
Spring 使用注解作为 XML 的一种替代方式,可用注解来配置项目。
- @Componentpublic class DependencyInjectionAnnotation {
- private String description;
- public String getDescription() {
- return description;
- }@Autowired public void setDescription(String description) {
- this.description = description;
- }
- }
@Component:表示被修饰的类,将被 Spring 容器实例化并管理。
@Autowired:Spring 容器将会尝试通过类型(这是一种元素匹配机制)使用这个 set 方法来自动装配。JAXB
JAXB 是一个用来相互转换和映射 XML 文件与 Java 对象的类库,这个类库与标准 JRE 一起提供,可直接引入 java.xml.bind.annotation 包下的类直接使用。
- @XmlType(propOrder = {
- "brand",
- "model",
- "year",
- "km"
- })@XmlRootElement(name = "Car") class Car {……
- }
上述声明一个类应该是 XML 文件中的一个节点,@XmlType、@XmlRoootElement 用来告知 JAXB 处理程序,这个 Car 类在转换后,将会成为 XML 中的一个节点。@XmlType 说明了属性在 XML 中的顺序。JAXB 将会基于这些注解执行合适的操作。
来源: http://www.92to.com/bangong/2017/06-20/23662544.html