java核心学习(十) 注解Annotation----上
一、java的五个自带的注解
@Override,方法重写的限定
@Deprecated,标记已过时
@SuppressWarnings,抑制编译器警告
@SafeVararges,抑制堆污染警告
@FunctionalInterface,标记函数式接口
二、JDK的元Annotation
元Annotation指 Annotation的Annotation,最根本的注解。在java8里共有六个元注解,其中五个·用于修饰其他注解的定义,另外一个用于定义java8新增的重复注解。
1、 @Retention 用于指定被修饰的Annotation可以保留多长时间,有且仅有一个名为value的成员变量,value的值仅能为如下三种
RetentionPolicy.CLASS 编译器把Annotation记录在class文件中,当运行java程序时,JVM不可以获取Annotation信息,不可以通过反射来获取Annotation信息,这也是value的默认值。
RetentionPolicy.RUNTIME 编译器把Annotation记录在class文件中,可利用反射在运行时获取Annotation信息,JVM也可以获取反射信息。
RetentionPolicy.SOURCE 只保留在java源代码中,在编译为class文件中丢弃之。
2、 @Target 用于指定被修饰的Annotation能用于修饰哪些程序单元,也仅含有一个value成员变量,其允许的值如下
ElementType.ANNOTATION_TYPE 指定该annotation只能用于修饰 Annotation
ElementType.CONSTRUCTOR 指定该注解只能用于修饰构造器
ElementType.FIELD 指定该注解只能修饰成员变量
ElementType.LOCAL_VARIABLE 指定该注解只能修饰局部变量
ElementType.METHOD 指定该注解只能修饰方法定义
ElementType.PACKAGE 指定该注解只能修饰包定义
ElementType.PARAMETER 指定该注解可以修饰参数
ElementType.TYPE 指定该注解可以修饰类、接口(包括注解类型)或枚举定义。
3、 @Documented 用于使用javadoc工具生成文档时加入注解,不赘述
4、 @inherited 指定被该注解修饰的类具有继承性
三、定义注解并使注解达到一定功能的实例
实例一、定义一个Testable来标记哪些方法是可以测试的
首先需要定义注解 @Testable ,定义注解就是定义注解的名字和上述的几个性质还有注解的内容(成员变量),注解本身只是对源代码添加一些特殊标记,注解本身并不会影响源代码,这些特殊标记可以被反射获取来编写注解的处理类。
定义注解的代码:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //定义注解的持续时间为Runtime,定义注解的目标为Method @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Testable { //该注解的功能为标记方法时候可被测试,不需要成员变量,仅仅只需要通过注解的有无来判断即可。 }
编写使用该注解的类
public class MyTest { @Testable public static void m1(){ } public static void m2(){ } @Testable public static void m3(){ throw new IllegalArgumentException("参数出错"); } public static void m4(){} @Testable public static void m5(){ } public static void m6(){ } @Testable public static void m7(){ throw new RuntimeException("程序业务出现异常"); } public static void m8(){} }
要想让上面MyTest类中的注解发挥作用,必须要编写注解的处理工具类,通过反射的方式来处理注解,这里用函数式接口来代替,真正处理注解的代码放在了main方法里
public interface ProcessorTest {
void process(String clazz) throws ClassNotFoundException;
}
main方法如下:
import java.lang.reflect.Method; public class RunTests { public static void process(String clazz,ProcessorTest processorTest) throws ClassNotFoundException{ processorTest.process(clazz); } public static void main(String[] args) throws ClassNotFoundException{ process("MyTest", new ProcessorTest() { @Override public void process(String clazz) throws ClassNotFoundException{ int passed = 0; int failed = 0; for (Method m:Class.forName("MyTest").getMethods() ) { //判断方法是否使用了@Testable来修饰 if(m.isAnnotationPresent(Testable.class)){ try { m.invoke(null); passed++; } catch (Exception e){ System.out.println("方法"+ m + "运行失败,异常:"+e.getCause()); failed++; } } } System.out.println("共运行了:"+(passed+failed)+"个方法,其中:\n失败了:"+failed+"个,\n成功了:"+passed+"个"); } }); } }
由于上面代码编译使用java7,所以无法使用lambda表达式。
运行结果如下
方法public static void MyTest.m3()运行失败,异常:java.lang.IllegalArgumentException: 参数出错 方法public static void MyTest.m7()运行失败,异常:java.lang.RuntimeException: 程序业务出现异常 共运行了:4个方法,其中: 失败了:2个, 成功了:2个 Process finished with exit code 0