注解

JDK内置预定义的注解:

* JDK中预定义的注解
 * @Override :检测该方法是否为父类中方法的重写
 * @Deprecated: 该注解标注的内容已过时
 * @SupperessWarnings: 压制警告

 1 package cn.ftf.annotation;
 2 /*
 3  * JDK中预定义的注解
 4  * @Override :检测该方法是否为父类中方法的重写
 5  * @Deprecated: 该注解标注的内容已过时
 6  * @SupperessWarnings: 压制警告
 7  */
 8 @SuppressWarnings(value = { "all" })   //压制警告,需要传值,一般传all
 9 public class Annotation01 {
10     public static void main(String[] args) {
11         
12     }
13     @Override    //重写toString方法,检查是否为父类中方法的重写
14     public String toString() {
15         // TODO Auto-generated method stub
16         return super.toString();
17     }
18     @Deprecated  //标识说明该方法已过时
19     public void shou1() {
20         //有缺陷
21     }
22     public void shou2() {
23         //替代shou1()方法
24     }
25     public void demo() {
26         shou1();
27     }
28 
29 }
30 
31 class Student{
32     
33 }

自定义注解:

 * 自定义注解
 * 格式
 *   元注解
 *   public @interface 注解名
 *  
 * 本质:
 *   注解本质上是一个接口,该接口默认继承Annotation接口
 *   public interface MyAnno extends java.lang.annotation.Annotation{}
 * 属性:
 *   接口中定义的抽象方法
 *   要求:
 *     属性的返回值有要求:基本数据类型,String,枚举,注解,以上类型的数组.定义了属性后,在使用时需要给他们赋值,也可以在注释中在属性后面用default给属性设值,如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接写值即可
 * 注解是否被子类继元注解:用于描述注解的注解
 *   @Target:描述注解可以作用的位置
 *   @Retention:描述注解被保留的阶段,一般都是保留到runtime阶段
 *   @Documented: 描述注解是否被抽取到API文档中
 *   @Inherited:描述注解是否可以被其子类继承

 

元注解:

 1 package cn.ftf.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Inherited;
 6 import java.lang.annotation.Retention;
 7 import java.lang.annotation.RetentionPolicy;
 8 import java.lang.annotation.Target;
 9 
10 /*
11  * 元注解:用于描述注解的注解
12  *   @Target:描述注解可以作用的位置
13  *   @Retention:描述注解被保留的阶段,一般都是保留到runtime阶段
14  *   @Documented: 描述注解是否被抽取到API文档中
15  *   @Inherited:描述是否可以继承到所继承的子类中
16  */
17 
18 @Target(value= {ElementType.TYPE})  //表示该注解只能作用在类上,可叠加.TYPE类上,.METHOD方法上,.FLELD成员变量上
19 @Retention(RetentionPolicy.RUNTIME)  //当前被描述的注解会被保留到class文件中,并被虚拟机(jvm)读取到
20 @Documented  //当前注解可以被抽取到API文档中
21 @Inherited  //当前注解可以被继承到所继承的子类中
22 public @interface MyAnno03 {
23 
24 }

 

 

首先定义一个注解:Myanno.java

1 package cn.ftf.annotation;
2 
3 public @interface MyAnno {
4     String name() default "张三";
5     int age();
6     Person per();  //枚举
7     MyAnno2 anno2();
8     String[] str();
9 }

一个枚举:Person.java:

1 package cn.ftf.annotation;
2 
3 public enum Person {
4     p1,p2;
5 }

 

 注解的声明和属性赋值:

 1 package cn.ftf.annotation;
 2 /*
 3  * 自定义注解
 4  * 格式
 5  *   元注解
 6  *   public @interface 注解名
 7  *   
 8  * 本质:
 9  *   注解本质上是一个接口,该接口默认继承Annotation接口
10  *   public interface MyAnno extends java.lang.annotation.Annotation{}
11  * 属性:
12  *   接口中定义的抽象方法
13  *   要求:
14  *     属性的返回值有要求:基本数据类型,String,枚举,注解,以上类型的数组.定义了属性后,在使用时需要给他们赋值,也可以在注释中在属性后面用default给属性设值,如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接写值即可
15  * 注解是否被子类继元注解:用于描述注解的注解
16  *   @Target:描述注解可以作用的位置
17  *   @Retention:描述注解被保留的阶段
18  *   @Documented: 描述注解是否被抽取到API文档中
19  *   @Inherited:描述注解是否可以被其子类继承
20  */
21 
22 @MyAnno(age = 20, per = Person.p1, anno2 = @MyAnno2, str = { "123","567" })  //注解声明和各种属性(方法)的赋值
23 public class AnnotationDemo02 {
24 
25 }

 

解析注解:

定义一个注解:Prp.java

 1 package cn.ftf.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
 8 
 9 /*
10  *描述需要执行的类名和方法名
11  */
12 @Target(ElementType.TYPE) //可以作用于类上
13 @Retention(RetentionPolicy.RUNTIME)  //会被保留到class文件中
14 public @interface Pro {
15     String className();
16     String methodName();
17 
18 }

对注解解析,拿到注解的属性:

 1 package cn.ftf.annotation;
 2 
 3 import java.lang.annotation.Annotation;
 4 
 5 @Pro(className = "cn.ftf.annotation.Demo1", methodName = "show")
 6 public class ReflectTest {
 7     public static void main(String[] args) {
 8         //解析注解
 9         //获取该类的字节码文件对象
10         Class<ReflectTest> c=ReflectTest.class;
11         //获取字节码文件的注解对象
12         Pro p=c.getAnnotation(Pro.class);  //其实就是在内存中生成生成了一个该注解接口的子类实现对象
13         String className=p.className();
14         String methodName=p.methodName();
15         System.out.println(className+"  "+methodName);  //拿到注解内容
16     }
17 }

 

 

下面应用注解和反射做一个简单的测试框架:

测试一个类(Calculaor类)中的方法是否有错误

 1 package cn.ftf.annotationpro;
 2 /*
 3  * 定义了一个计算机的类
 4  */
 5 public class Calculator {
 6     @Check
 7     public void add() {
 8         System.out.println("1+0="+(1+0));
 9     }
10     @Check
11     public void del() {
12         System.out.println("1-0="+(1-0));
13     }
14     @Check
15     public void mul() {
16         System.out.println("1*0="+(1*0));
17     }
18     @Check
19     public void div() {  //显然div方法中由错误(by zero)
20         System.out.println("1/0="+1/0);
21     }
22     public void show() {
23         System.out.println("永无bug...");
24     }
25 }

 

定义一个接口:Check.java

 1 package cn.ftf.annotationpro;
 2 
 3 import java.lang.annotation.ElementType;
 4 import java.lang.annotation.Retention;
 5 import java.lang.annotation.RetentionPolicy;
 6 import java.lang.annotation.Target;
 7 
 8 @Target(ElementType.METHOD)
 9 @Retention(RetentionPolicy.RUNTIME)
10 public @interface Check {
11 }

定义测试类TestCheck.java:

 1 package cn.ftf.annotationpro;
 2 
 3 import java.io.BufferedWriter;
 4 import java.io.FileWriter;
 5 import java.io.IOException;
 6 import java.lang.reflect.InvocationTargetException;
 7 import java.lang.reflect.Method;
 8 
 9 /*
10  * 简单的测试类,当主方法执行,会检测该类下所有的需要检测的方法,并记录到文件中
11  */
12 public class TestCheck {
13     public static void main(String[] args) throws IOException {
14         //获取要检测的类的计算器对象
15         Calculator cal= new Calculator();
16         //获取字节码文件对象
17         Class c=cal.getClass();
18         
19         //获取所有的方法
20         Method[] me=c.getMethods();
21         int number =0;  //记录出现异常的次数
22         BufferedWriter bw=new BufferedWriter(new FileWriter("D:\\myjavacode\\ftf001\\src\\cn\\ftf\\annotationpro\\bugNote.txt"));
23         //方法上是否由check注解
24         for(Method m:me) {
25             if(m.isAnnotationPresent(Check.class)) {
26                     try {
27                         m.invoke(cal);
28                     } catch (Exception e) {
29                         number++;
30                         //记录到文件中
31                         bw.write(m.getName()+"方法出异常了!");
32                         bw.newLine();
33                         bw.write("异常名称:"+e.getCause().getClass().getSimpleName());
34                         bw.newLine();
35                         bw.write("异常原因:");
36                         bw.write(e.getCause().getMessage());
37                         bw.newLine();
38                         
39                     }
40             }
41         }
42         bw.write("本次一共出现"+number+"次异常!");
43         bw.close();
44     }
45 }

结果:

 

posted @ 2019-08-01 21:22  codeFlyer  阅读(182)  评论(0)    收藏  举报