14.3 自定义注解 14.3.1 定义注解

14.3 自定义注解

前面已经介绍了如何使用java.lang包下的4个基本的注解,下面介绍如何自定义注解,并利用注解来完成一些实际的功能

14.3.1 定义注解

示例 定义注解

定义新的注解类型使用@interface关键字(在原有的interface关键字前增加@符号)定义一个新的注解类型与定义一个接口非常像,如下代码可定义一个简单的注解类型。

1
2
3
4
//定义一个简单的注解类型
public @interface Test{

}

定义了该注解之后,就可以在程序的任何地方使用该注解,使用注解的语法非常类似于publicfinal这样的修饰符,通常可用于修饰程序中的类、方法、变量、接口等定义。通常会把注解放在所有修饰符之前,而且由于使用注解时可能还需要为成员变量指定值,因而注解的长度可能较长,所以通常把注解另放一行,如下程序所示

示例 注解修饰类

1
2
3
4
5
//使用 @Test修饰类定义
@Test
public class MyClass{

}

示例 注解修饰方法

在默认情况下,注解可用于修饰任何程序元素,包括类、接口、方法等,如下程序使用@Test来修饰方法

1
2
3
4
5
6
7
8
public class MyClass
{
//使用 @Test注解修饰方法
@Test
public void info (){

}
}

带成员变量的注解

注解不仅可以是这种简单的注解,还可以带成员变量,成员变量在注解定义中以无形参的方法形式来声明,其方法名和返回值定义了该成员变量的名字和类型。如下代码可以定义一个有成员变量的注解。

1
2
3
4
5
6
public @interface MyTag{
//定义带两个成员变量的注解
//注解中的成员变量以方法的形式来定义
String name();
int age();
}

自定义注解继承Annotation接口

可能有读者会看出,上面定义注解的代码与定义接口的语法非常像,只是MyTag使用 @interface关键字来定义,而接口使用interface来定义。
使用@interface定义的注解的确非常像定义了一个注解接口,这个注解接口继承了java.lang.annotation.Annotation接口,这一点可以通过反射看到MyTag接口里包含了java.lang.annotation.Annotation接口里的方法。

给注解的成员变量赋值

一旦在注解里定义了成员变量之后,使用该注解时就应该为它的成员变量指定值,如下代码所示。

1
2
3
4
5
6
7
public class Test{
//使用带成员变量的注解时,需要为成员变量赋值
@MyTag(name="xx", age=6);
public void info(){

}
}

为注解的成员变量指定默认值

也可以在定义注解的成员变量时为其指定初始值(默认值),指定成员变量的初始值可使用default关键字。如下代码定义了@MyTag注解,该注解里包含了两个成员变量:nameage,这两个成员变量使用default指定了初始值。

1
2
3
4
5
6
7
public @interface MyTag
{
//定义了两个成员变量的注解
//使用 default为两个成员变量指定初始值
string name() default "HelloWorld";
int age() default 32;
}

如果为注解的成员变量指定了默认值,使用该注解时则可以不为这些成员变量指定值,而是直接使用默认值。

1
2
3
4
5
6
7
8
9
public class Test
{
//使用带成员变量的注解
//因为它的成员变量有默认值,所以可以不为它的成员变量指定值
@MyTag
public void info(){

}
}

当然也可以在使用MyTag注解时为成员变量指定值,如果为MyTag的成员变量指定了值,则默认值不会起作用。

根据有无成员变量为注解分类

根据注解是否可以包含成员变量,可以把注解分为如下两类。

  1. 标记注解:没有定义成员变量的注解类型被称为标记。这种注解仅利用自身的存在与否来提供信息,如前面介绍的@Override@Test等注解。
  2. 元数据注解:包含成员变量的注解,因为它们可以接受更多的元数据,所以也被称为元数据注解,