【重难点】注解

一、概念

1、概念--Annotation

是 JDK5.0 引入的一种注释机制。 Java 语言中的类、方法、变量、参数和包等都可以被标注,用于说明程序,给计算机看。

(注释:用文字描述 程序,给程序员看)

2、使用:

  • @注解名称
  • @Override重写
  • @Test

3、作用

  • 编译检查
  • 生成doc文档【文档注释】
    • javadoc HelloWorld.java
    • /**
    • *@author ljh
    • */
  • 代码分析

4、常见的内置注解(Java预定义的注解)

  • @Override:检查是否是重写(父类/接口)的方法
  • @Deprecated:标记过时方法,编译时会警告
  • @SuppressWarnings/@SuppressWarnings("all"):忽略注解中声明的警告 

二、自定义注解

1、格式

  元注解
public @interface 注解名称(){
     属性列表
}

2、本质

反编译后

 

 

 本质上是一个接口,该接口默认继承Annotation 接口

Annotation 接口:所有注释类型扩展的公共接口,手动扩展这个接口不限定注释类型,此接口本身并不定义注释类型。
3、属性

接口中可以定义的抽象成员方法

要求

  • 属性方法返回值
    • 基本数据类型
    • String
    • 枚举
    • 注解
    • 上述类型的数组
    • 不包括void空类型
  • 使用时需要给属性赋值
    • 数组赋值时需要使用{}包裹,一个元素可以省略
    • 只有一个属性需要赋值且属性名为value时,可只写值省略value
    • @SuppressWarnings("all")的属性是一个字符数组String[] value;
 1 package com.liujinhui.Day1209BaseEnhance.annotation;
 2 public @interface MyAnno {
 3     int age();
 4    String name() default "张三";
 5     Person per();
 6     MyAnno2 anno2();
 7     String[] show3();
 8 }
 9 
10   @MyAnno(age = 1,name="张三")//所以称为属性
11     public void demo(){
12         show1();
13         Date date=new Date();
14     }

4、元注解:描述注解的注解

1 @Target(ElementType.METHOD)//作用位置:方法
2 @Retention(RetentionPolicy.SOURCE)//能被保留到什么阶段:Source源码阶段
3 public @interface ZJName {
4 }
  • @Documented:描述 注解是否被抽取到API文档中 
  • @Inherited:描述注解是否被子类继承,加注解后,子类会自动继承父类的注解
  • @Target:描述注解能够作用的位置
    • @Target(value = {ElementType.TYPE})//表示该Anno3注解可以作用于类上
    • @Target(value = {ElementType.METHOD})//表示该Anno3注解可以作用于方法上

    • @Target(value = {ElementType.FIELD})//表示该Anno3注解可以作用于成员变量上

    • @Target(value = {ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})

  • @Retention:描述注解被保留的阶段(Source/Class/Runtime)
    • @Retention(RetentionPolicy.RUNTIME)当前被描述的注解,会保留到class字节码文件中,并被JVM读取到

  

 

使用:自定义@MyAnno3注解

1 import java.lang.annotation.*;
2 @Target(value = {ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
3 @Retention(RetentionPolicy.RUNTIME)
4 @Documented
5 //可以抽取到文档中
6 @Inherited
7 public @interface MyAnno3 {
8 }

5、解析注解:获取注解中的属性值

步骤:

  • 获取注解定义的位置的对象(Class,Method,Field)
  • 获取指定注解 getAnnotation(Class)

 1 //其实就是在内存中生成了一个该注解接口的子类实现对象
 2 public class ProIMpl implements Pro{
 3       public String className(){
 4           return"com.liujinhui.Day1209BaseEnhance.annotation.Demo1";
 6       }
 7       public String methodName(){
 8            return "show";
 9       }
10 }
  • 调用注解中的抽象方法获取配置的属性值

 三、案例

1、自定义注解执行任意类的任意方法

1 package com.liujinhui.Day1209BaseEnhance.annotation;
2 
3 public class Demo1 {
4     public void show(){
5         System.out.println("demo1 show");
6     }
7 }
 1 package com.liujinhui.Day1209BaseEnhance.annotation;
 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 /*
 9     描述需要执行的类名和方法名
10  */
11 @Target({ElementType.TYPE})
12 @Retention(RetentionPolicy.RUNTIME)
13 public @interface Pro {
14     String className();
15     String methodName();
16 }
17 /*
18     public class ProIMpl implements Pro{
19            public String className(){
20                 return  "com.liujinhui.Day1209BaseEnhance.annotation.Demo1";
21            }
22            public String methodName(){
23                 return "show";
24            }
25 
26  */
 1 package com.liujinhui.Day1209BaseEnhance.annotation;
 2 import java.io.InputStream;
 3 import java.lang.reflect.Method;
 4 import java.util.Properties;
 5 /*
 6     假设的框架类
 7     改配置文件使程序的扩展性更强,配置文件中使用了全类名,则使用了反射机制
 8 * */
 9 @Pro(className = "com.liujinhui.Day1209BaseEnhance.annotation.Demo1",methodName = "show")
10 //要写全类名
11 public class ReflectTest {
12     /**
13      * @author: Liu Jinhui
14      * @description: 创建任意对象
15      * @date: 2020/12/9 20:42
16      * @return  * @param null
17      */
18     public static void main(String[] args) throws Exception{
19         //可以创建任意类的对象,可以执行任意方法
20         /*
21             前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法
22         * */
23         //1.解析注解
24         //1.1获取该类的字节码文件对象
25         Class<ReflectTest> reflectTestClass = ReflectTest.class;
26         //2.获取上面的注解对象
27         //method也有getAnno
28         Pro an = reflectTestClass.getAnnotation(Pro.class);
29         //其实就是在内存中生成了一个该注解接口的子类实现对象
30         /*
31             public class ProIMpl implements Pro{
32                    public String className(){
33                         return  "com.liujinhui.Day1209BaseEnhance.annotation.Demo1";
34                    }
35                    public String methodName(){
36                         return "show";
37                    }
38          */
39         //3.调用注解对象中调用的抽象方法,获取返回值
40         String className = an.className();
41         String methodName = an.methodName();
42         System.out.println(className+methodName);
43         //4.加载该类进内存
44         Class cls = Class.forName(className);
45         //5.创建对象
46         Object obj = cls.newInstance();
47         //6.获取方法对象
48         Method method = cls.getMethod(methodName);
49         //7.执行方法
50         method.invoke(obj);
51     }
52 }

2、通过注解实现简单的测试框架

要求:

当主方法执行后,会自动执行被检测的所有方法(加了@Check的方法)
 1 package com.liujinhui.Day1209BaseEnhance.annotation.demo;
 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(value = {ElementType.METHOD})
 9 @Retention(RetentionPolicy.RUNTIME)
10 @interface Check {
11 }
 1 package com.liujinhui.Day1209BaseEnhance.annotation.demo;
 2 
 3 /**
 4  * 小明定义的计算器类
 5  * 需要测试是否有错误
 6  */
 7 public class Calculator {
 8     //加法
 9     @Check
10     public void add(){
11         System.out.println("1+0="+(1+0));
12     }
13     //减法
14     @Check
15     public void sub(){
16         System.out.println("1 - 0 ="+(1 - 0));
17     }
18     //乘法
19     @Check
20     public void mul(){
21         System.out.println("1*0="+(1*0));
22     }
23     //除法
24     @Check
25     public void div(){
26         System.out.println("1/0="+(1/0));
27     }
28     //结果
29     public void show(){
30         System.out.println("永无bug...");
31     }
32 }
 1 package com.liujinhui.Day1209BaseEnhance.annotation.demo;
 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  * 当主方法执行后,会自动执行被检测的所有方法(加了@Check的方法)
12  * 判断方法是否有异常,并记录到文件中
13  */
14 public class TestCheck {
15     public static void main(String[] args) throws IOException {
16         //1.创建计算器对象
17         Calculator c = new Calculator();
18         //2.获取字节码文件对象
19         Class cls = c.getClass();
20         //3.获取所有的方法
21         Method[] methods = cls.getMethods();
22         int number=0;//记录异常出现的次数
23         BufferedWriter bw=new BufferedWriter(new FileWriter("bug.txt"));
24         for (Method method : methods) {
25             //4.判断方法上是否有check注解
26             if (method.isAnnotationPresent(Check.class)) {
27                 //判断当前方法上有无指定注解
28                 //5.有就执行该方法
29                 try {
30                     method.invoke(c);
31                 } catch (Exception e) {
32                     //6.捕获异常
33                     number++;
34                     //记录到文件中
35                     bw.write(method.getName() + "方法出异常了");
36                     bw.newLine();
37                     bw.write("异常的名称:" + e.getCause().getClass().getSimpleName());
38                     bw.newLine();
39                     bw.write("异常的原因:" + e.getCause().getMessage());
40                     bw.newLine();
41                     bw.write("-----------------------");
42                 }
43             }
44         }
45         bw.write("本次测试共出现"+ number +"次异常");
46         bw.flush();
47         bw.close();
48     }
49 }

3、总结

  • 常用jdk内置注解而不是自定义注解
  • 注解给编译器解析程序用
  • 注解不是程序的一部分,而是相当于程序的标签

     

 

 

 

posted @ 2021-01-19 10:24  哥们要飞  阅读(86)  评论(0)    收藏  举报