Java工作笔记-注解的进一步理解
发布日期:2021-06-30 10:41:04 浏览次数:2 分类:技术文章

本文共 5385 字,大约阅读时间需要 17 分钟。

目录

 

 


 

基本概念

注解:说明程序,给计算机看的。

注释:给程序员看的。

 

作用分类:

编写文档:通过代码里标识的注解生成文档javadoc(生成doc文档)

代码分析:通过代码里标识的注解对代码进行分析(使用反射)

编译检查:通过代码里标识的注解人编译器能够实现基本的编译检测(Override)

 

JDK中预定义的注解:

@Override:检测被该注释标注的方法是否继承自父类(接口)

@Deprecated:该注解标注的内容,已经过时

@SuppressWarnings:压制警告

 

这里提示下:@SuppressWarnings("all")一般是这么用的

 

代码与实例

下面来看下自定义注解,格式如下:

元注解

public @interface 注解名称{}

注解的本质,实际上是接口:

如下代码:

package demo;public @interface AnnoDemo1 {    }

目前先使用javac让其生成字节码文件,再使用javap逆向生成类:

从中可以看到注解的本质就是接口.

注解(接口)中的属性:

          要求:
          1. 属性的返回值类型:基本数据类型、String、枚举、注解、以上类型的数组;
          2. 定义了属性,在使用时需要给属性赋值;
             1. 如果定义属性时,使用default关键字给属性设置默认值,则使用注解时,可以不进行属性的赋值。
             2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义即可。
             3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}省略

如下代码:

Person.java

package demo;public enum  Person {    p1, p2}

AnnoDemo1.java

package demo;public @interface AnnoDemo1 {    int show1();    String show2();    Person per();    AnnoDemo2 anno2();    String[] strs();}

AnnoDemo2.java

package demo;public @interface AnnoDemo2 {    int age();    String name() default "王二麻子";}

Worker.java

package demo;@AnnoDemo1(show1 = 1, show2 = "Hello", per = Person.p1, anno2 = @AnnoDemo2(age = 12), strs = {"1", "2"})public class Worker {}

下面是关于元注解相关:

元注解:

          @Target:描述注解能够作用的位置;
                    ElementTYpe取值:
                         TYPE:可以作用于类上
                         METHOD:作用于方法上
                         FIELD:用于成员变量
          @Retention:描述注解被保留的阶段;
                     @Retention(RetentionPolicy.RUNTIME):保留class字节码文件中,并被JVM读取。
          @Decumented:描述注解是否被抽到API文档中;
          @Inherited:描述注解是否被子类继承。

这里要注意:自定义注解一般使用runtime

后期注解大多数都是用于替换配置文件的

如下:

AnnoDemo3.java

package demo;import java.lang.annotation.*;@Target(value = {ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface AnnoDemo3 {}

注解中:

package demo;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface pro {    String className();    String methodName();}

这个注解,实际上会生成这样的字节码文件,这个个人感觉和Qt中带有Q_OBJECT和集成了QObject类,生成moc的技术有异曲同工之妙。

public class ProImpl implements Pro{     public String className(){}     public String methodName(){}}

 

下面是使用注解来实现配置文件的加载

如下的例子:

Pro.java

package demo;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Pro {    String className();    String methodName();}

MainTest.java

import demo.Pro;import java.lang.reflect.Method;@Pro(className = "demo.Test", methodName = "show")public class MainTest {    public static void main(String[] arg) throws Exception{        //解析注释,获取该类的字节码文件对象        Class mainTestClass = MainTest.class;        //获取注解对象,内存中生成了一个该注解接口的子类实例        Pro annotation = (Pro) mainTestClass.getAnnotation(Pro.class);        //调用抽象方法,获取数据        String s = annotation.className();        String s1 = annotation.methodName();        //加载该类进内存        Class aClass = Class.forName(s);        //创建对象        Object o = aClass.newInstance();        //获取方法对象        Method method = aClass.getMethod(s1);        //执行方法        method.invoke(o);    }}

在程序使用(解析)注解:获取注解中定义的属性值:

     1. 获取注解定义的位置的对象(Class,Method,Field)
     2. 获取指定的注解:
            getAnnotation(Class)
     3. 调用注解中的抽象方法获取配置的属性值。

 

下面是一个综合案例,通过注解完成,某个函数的测试功能。

统计一个类中,不抛异常的函数个数:

程序运行截图如下:

错误文件:

源码如下:

Calculator.java

package demo2;public class Calculator {    @Check    public void add(){        System.out.println("1 + 0 = " + (1 + 0));    }    @Check    public void sub(){        System.out.println("1 - 0 = " + (1 - 0));    }    @Check    public void mul(){        System.out.println("1 * 0 = " + (1 * 0));    }    @Check    public void div(){        System.out.println("1 / 0 = " + (1 / 0));    }}

Check.java

package demo2;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)public @interface Check {}

MainTest2.java

import demo2.Calculator;import demo2.Check;import java.io.BufferedWriter;import java.io.FileWriter;import java.lang.reflect.Method;public class MainTest2 {    public static void main(String[] arg) throws Exception{        //创建计算器对象        Calculator c = new Calculator();        //获取字节码文件对象        Class cls = c.getClass();        //获取所有方法        Method[] methods = cls.getMethods();        int number = 0;//出现异常的此数        BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));        for(Method method : methods){            //判断方法上是否有Check注解            if(method.isAnnotationPresent(Check.class)){                //有就执行                try{                    method.invoke(c);                }                catch (Exception e){                    //获取异常,记录到文件                    number++;                    bw.write(method.getName() + "方法出现异常");                    bw.newLine();                    bw.write("异常名称:" + e.getCause().getClass().getSimpleName());                    bw.newLine();                    bw.write("异常原因:" + e.getCause().getMessage());                    bw.newLine();                    bw.write("------------------------------");                }            }        }        bw.newLine();        bw.write("本次测试一共出现 " + number + " 次异常");        bw.flush();        bw.close();    }}

注解不是程序的一部分,是给编译器看的,可以理解为注解是一个标签。

源码打包下载地址:

 

转载地址:https://it1995.blog.csdn.net/article/details/103578437 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:SQL工作笔记-达梦存储过程及时间触发器实现自动生成数据
下一篇:Java工作笔记-对反射的进一步理解

发表评论

最新留言

逛到本站,mark一下
[***.202.152.39]2024年04月17日 11时47分36秒