本文共 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 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!