一、OverView
注解在JavaSE中属于一种高级的用法,在项目以及很多的框架结构中都使用到了注解这种特殊用法,注解是在JDK1.5之后的一个新特性。在我们开始编写Java代码的时候,经常会在代码中生成@Override(重写) @Deprecated(f废弃的) @SuppressWarnings(压缩警告),这是在JDK1.5之后提供的常用注解。
首先来一段小的Code,预热一下。
public class Demo{
public static void main(String[] args) {
funDeprecated();
}
@Deprecated
public static void funDeprecated(){
System.out.println("这是一个过期的方法");
}
public Thread createThread() {
return new Thread(new Runnable() {
@Override
public void run() {
System.out.println("这是一个重写的方法");
}
});
}
@SuppressWarnings({ "unused", "resource" })
public void readFile(String path) throws FileNotFoundException{
File f = new File(path);//unused一个
InputStream stream = new FileInputStream(path);//unused resource两个
}
}
在很多博客及书籍的地方有的将Annotation称为“注释”,其实是不对的,注释和注解是两个完全不同的概念,注解具有非常浓重的“Code”色彩,这个特性是注释完全不能表达的。注释给编程、测试人员看的,而注解有一部分是面向程序员的,但是更多的是面向于编译器的。注解简单的讲就是一种标记方式,在程序的特定的方式打上标记,这样编译器等工具就可以在相应的位置进行处理。注解可以标记在package , class , field , method , parameter , local variable之上。
二、Meta Annotation
元注解(Meta Annotation)是注解的注解,就是在定义注解的时候使用的注解,用来控制自定义注解的最作用对象,生命周期等特性。
2.1 @Retention
Java在编译的过程中主要经理了3个阶段:
(1) 编程人员编写得到java源代码(.java) -------------------------》RetentionPolicy.SOURCE
(2) 使用javac将java源代码编译成为.class文件 -------------------------》RetentionPolicy.CLASS
(3) JVM将class文件解释成为字节码文件(0,1组合的二进制) -----------------》RetentionPolicy.RUNTIME
RetentionPolicy.RUNTIME可以让你从JVM中读取Annotation注解的相关信息,以便在程序分析的时候使用。
上述的三个值对应了java程序对应的三个阶段,当为自定义注解添加了对应的生命周期后,一旦对应的java阶段完成之后就会将该注解去掉。例如:加入一个注解添加了@Retention(RetentionPolicy.RUNTIME) 这样的注解,那么在编译成class文件之后该注解就去掉了。
在JAVA中常见的三种注解 @Override @SuppressWarnings的生命周期是SOURCE , @Deprecated的生命周期是RUNTIME
2.2 @Target
Target可以控制自定义注解的作用对象,如field method等。使用方法为:
@Target(ElementType.FIELD)
Tips:如果注解中有value属性而且你在使用它,那么可以省略value =****,直接写属性值,就像上面@Target一样,也就是上述注解的完整写法是:
@Target(value = ElementType.FIELD)
三、Instruction
3.1 注解的定义
注解的定义格式和类十分相似,也有对应的属性,具体的语法格式为:
元注解
public @interface 注解名{
属性定义[默认值]
}
eg:
@Retention(Retentionpolicy.SOURCE)
@Target({ElementType.METHOD,ElementType.Field})
public @interface DemoAnnotation{
String classPath(); //注意属性定义的时候有一个括号
int endIndex() default 10; //为属性添加一个默认值
}
3.2 注解的使用和获取
注解的使用和元注解一样,注解的获取通过相应类的class对象的getAnnotation方法获得。
@DemoAnnotation(classPath="com.test.mycode.impl.UserAction")
public class Demo{
public static void main(String[] args)
{
DemoAnnotation annotation = (
DemoAnnotation)Demo.getClass().getAnnotation(DemoAnnotation.class);
System.out.println(annotation.classPath);
System.out.println(annotation.endIndex);
}
}
3.3 注解属性的一些扩展
注解的属性除了常规的int float String等类型外,我们还可以定义一些其他类型,如数组、枚举类型等。
数组:
String[] name() default {"AAA","BBB","CCC"} 使用的时候 @DemoAnnotation(name ={"aaa","bbb","ccc"})
SexType sex() default SexType.Male 其中SexType是一个枚举类型
四、Demo
下面是一些综合练习
package com.test.mycode.main;
/**
* 描述任务的优先级
*
*/
public enum PriorityStatus {
HIGH,
MEDIUM,
LOW
}
package com.test.mycode.main;
/**
*
* 设置一个元注解
*
*/
public @interface MetaAnnotation {
String value();
}
package com.test.mycode.main;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface TaskAnnotation {
String classPath();
String value();
int[] arrayCode() default {1,2,3};
PriorityStatus status() default PriorityStatus.HIGH;
MetaAnnotation annotation() default @MetaAnnotation("mytask");
}
package com.test.mycode.main;
@TaskAnnotation(
classPath="com.test.mycode.MyTest",
value = "MyTest",
arrayCode = {4,2,8},
status = PriorityStatus.HIGH,
annotation = @MetaAnnotation("mytask")
)
public class MyTest {
public static void main(String[] args) {
if(MyTest.class.isAnnotationPresent(TaskAnnotation.class)) {//判断是否有该类型的注解
//得到注解
TaskAnnotation taskAnnotation = (TaskAnnotation)MyTest.class.getAnnotation(TaskAnnotation.class);
System.out.println(taskAnnotation.classPath());
System.out.println(taskAnnotation.value());
System.out.println(taskAnnotation.arrayCode());
System.out.println(taskAnnotation.status());
System.out.println(taskAnnotation.annotation().value());
}
}
}