一、最常见注解
@Override
属于标记注解,不需要设置属性值;只能添加在方法的前面,用于标记该方法是复写的父类中的某个方法,如果在父类没有的方法前面加上@Override注解,编译器会报错:
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Deprecated
 属于标记注解,不需要设置属性值;可以对构造方法、变量、方法、包、参数标记,告知用户和编译器被标记的内容已不建议被使用,如果被使用,编译器会报警告,但不会报错,程序也能正常运行:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.LOCAL_VARIABLE, ElementType.METHOD, ElementType.PACKAGE, ElementType.PARAMETER, ElementType.TYPE})
public @interface Deprecated {
}
@SuppressWarnings
 可以对构造方法、变量、方法、包、参数标记,用于告知编译器忽略指定的警告,不用再编译完成后出现警告信息:
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.CONSTRUCTOR, ElementType.LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
二、元注解
通过阅读注解类的源码可以发现,任何一个注解类都有如下特征:
-
注解类会被@interface标记;
-
注解类的顶部会被@Documented、@Retention、@Target、@Inherited这四个注解标记(@Documented、@Inherited可选,@Retention、@Target必须要有);
上文提到的四个注解:@Documented、@Retention、@Target、@Inherited就是元注解,它们的作用是负责注解其它注解,主要是描述注解的一些属性,任何注解都离不开元注解(包括元注解自身,通过元注解可以自定义注解),元注解的用户是JDK,JDK已经帮助我们实现了这四个注解的逻辑。这四个注解在JDK的java.lang.annotation包中。对每个元注解的详细说明如下:
- @Target:
作用:用于描述注解的使用范围,即被描述的注解可以用在什么地方;
取值:
- CONSTRUCTOR:构造器;
- FIELD:实例;
- LOCAL_VARIABLE:局部变量;
- METHOD:方法;
- PACKAGE:包;
- PARAMETER:参数;
- TYPE:类、接口(包括注解类型) 或enum声明。
示例:
/***
*
* 实体注解接口
*/
@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface Entity {
/***
* 实体默认firstLevelCache属性为false
* @return boolean
*/
boolean firstLevelCache() default false;
/***
* 实体默认secondLevelCache属性为false
* @return boolean
*/
boolean secondLevelCache() default true;
/***
* 表名默认为空
* @return String
*/
String tableName() default "";
/***
* 默认以""分割注解
*/
String split() default "";
}
- @Retention:
作用:表示需要在什么级别保存该注解信息,用于描述注解的生命周期,即被描述的注解在什么范围内有效;
取值:
- SOURCE:在源文件中有效,即源文件保留;
- CLASS:在class文件中有效,即class保留;
- RUNTIME:在运行时有效,即运行时保留;
示例:
/***
* 字段注解接口
*/
@Target(value = {ElementType.FIELD})//注解可以被添加在实例上
@Retention(value = RetentionPolicy.RUNTIME)//注解保存在JVM运行时刻,能够在运行时刻通过反射API来获取到注解的信息
public @interface Column {
String name();//注解的name属性
}
- @Documented:
作用:用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。
取值:它属于标记注解,没有成员;
示例:
@Documented
@Retention(CLASS)
@Target({METHOD,CONSTRUCTOR,TYPE})
public @interface UiThread {
}
- @Inherited:
作用:用于描述某个被标注的类型是可被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
取值:它属于标记注解,没有成员;
示例:
/**
* @author wangsheng
**/
@Inherited
public @interface Greeting {
public enum FontColor{ BULE,RED,GREEN};
String name();
FontColor fontColor() default FontColor.GREEN;
}
三、如何自定义注解
使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。
-
自定义注解格式:
元注解 public @interface 注解名{ 定义体; }
-
注解参数可支持的数据类型:
所有基本数据类型(int,float,boolean,byte,double,char,long,short);
- String类型;
- Class类型;
- enum类型;
- Annotation类型;
- 以上所有类型的数组。
特别说明:
1、注解类中的方法只能用public或者默认这两个访问权修饰,不写public就是默认,eg:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {
public enum Color{ BULE,RED,GREEN};
Color fruitColor() default Color.GREEN;
}
2、如果注解类中只有一个成员,最好把方法名设置为"value",比如:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {
String value() default "";
}
3、注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。
- 实例演示:
ToDo.java:注解类
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Todo {
public enum Priority {LOW, MEDIUM, HIGH}
public enum Status {STARTED, NOT_STARTED}
String author() default "Yash";
Priority priority() default Priority.LOW;
Status status() default Status.NOT_STARTED;
}
BusinessLogic:使用注解的类
public class BusinessLogic {
public BusinessLogic() {
super();
}
public void compltedMethod() {
System.out.println("This method is complete");
}
@Todo(priority = Todo.Priority.HIGH)
public void notYetStartedMethod() {
// No Code Written yet
}
@Todo(priority = Todo.Priority.MEDIUM, author = "Uday", status = Todo.Status.STARTED)
public void incompleteMethod1() {
//Some business logic is written
//But its not complete yet
}
@Todo(priority = Todo.Priority.LOW, status = Todo.Status.STARTED )
public void incompleteMethod2() {
//Some business logic is written
//But its not complete yet
}
}
TodoReport.java:解析注解信息
public class TodoReport {
public TodoReport() {
super();
}
public static void main(String[] args) {
getTodoReportForBusinessLogic();
}
/**
* 解析使用注解的类,获取通过注解设置的属性
*/
private static void getTodoReportForBusinessLogic() {
Class businessLogicClass = BusinessLogic.class;
for(Method method : businessLogicClass.getMethods()) {
Todo todoAnnotation = (Todo)method.getAnnotation(Todo.class);
if(todoAnnotation != null) {
System.out.println(" Method Name : " + method.getName());
System.out.println(" Author : " + todoAnnotation.author());
System.out.println(" Priority : " + todoAnnotation.priority());
System.out.println(" Status : " + todoAnnotation.status());
System.out.println(" --------------------------- ");
}
}
}
}
执行结果如下图所示: