JAVA自定义注解,java自定义注解怎么生效的
00-1010概念函数JDK注释中预定义的一些注释生成文档用例自定义注释格式本质属性:接口元注释中的抽象方法:用于描述注释的注释用于程序(解析)注释:获取注释用例中定义的属性值:通过自定义注释定义一个简单的测试框架摘要。
00-1010概念:解释程序。为了电脑。
注释:用文字描述程序。对于程序员来说。
定义:注释,也称为元数据。代码级别的描述。是JDK1.5及以后版本引入的特性,和类、接口、枚举是一个级别的。可以在包、类、字段、方法、局部变量、方法参数等前面声明。来解释和评论这些元素。
00-1010功能分类:
写文档:通过代码中标识的注释生成文档【生成文档doc文档】代码分析:通过代码中标识的注释分析代码【使用反射】编译检查:通过代码中标识的注释使编译器实现基本编译检查【覆盖】。
目录
@Override:检查此注释标记的方法是否继承自父类(接口)
@Deprecated:此评论标记的内容表示已经过时。
@SuppressWarnings:取消警告
传递常规参数all @SuppressWarnings(all )
00-1010 api类案例生成doc文档:
/* * * Note javadoc demo * * @ AuthorZJQ * @ version 1.0 * @ since 1.5 */public class annodoc {/* * *计算两个数之和* @ param a integer * @ param b integer * @ return两个数之和*/public int add (int a,int b){ return a b;}}在相应的类目录中输入cmd并执行以下命令
执行JavaDoc AnnoDoc.java后,可以看到已经生成了很多html、js等前端文件。单击index.html。您可以看到以下效果:
概念
00-1010元标注public @interface标注名称{属性列表;}
00-1010 Annotation本质上是一个接口,默认继承Annotation接口。
公共接口MyAnno扩展Java . lang . annotation . annotation { }
00-1010要求:
1.属性的返回值类型具有以下值
基本数据类型
线
列举
给…作注解
以上类型的数组
2.定义了属性,使用时需要赋值。
如果default关键字用于在定义属性时初始化属性的默认值,则可以不带注释地分配属性。如果只需要分配一个属性,并且属性的名称是value,那么可以省略value,直接定义value。分配数组时,该值用{}包装。如果数组中只有一个值,{}可以省略这种情况:
定义
public @ interface MyAnno { int value();每人();myanno 2 anno 2();string[]strs();}公共枚举人{ P1,P2;}使用
@MyAnno(值=12,每人=人。P1,anno2=@MyAnno2,strs=bbb )公共类Worker { }
00-1010@Target:描述了注释可以工作的位置。
ElementType值:类型:可以作用于类;方法:可以作用于
方法上FIELD:可以作用于成员变量上@Retention:描述注解被保留的阶段
@Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到,自定义注解一般用这个。
@Documented:描述注解是否被抽取到api文档中
@Inherited:描述注解是否被子类继承
在程序使用(解析)注解:获取注解中定义的属性值
之前我们在反射中有通过读取配置文件来创建任意类的对象,执行任意方法。具体反射内容可以看我的这篇文章:Java框架设计灵魂之反射的示例详解
之前反射中我们通过读取对应的配置文件然后创建类和执行方法,代码如下:
/**前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法*/ //1.加载配置文件//1.1创建Properties对象Properties pro = new Properties();//1.2加载配置文件,转换为一个集合//1.2.1获取class目录下的配置文件ClassLoader classLoader = ReflectTest.class.getClassLoader();InputStream is = classLoader.getResourceAsStream("pro.properties");pro.load(is); //2.获取配置文件中定义的数据String className = pro.getProperty("className");String methodName = pro.getProperty("methodName"); //3.加载该类进内存Class cls = Class.forName(className);//4.创建对象Object obj = cls.newInstance();//5.获取方法对象Method method = cls.getMethod(methodName);//6.执行方法method.invoke(obj);
我们可以通过注解替换上述读取配置文件相关操作。具体代码如下:
注解定义如下:
/** * 描述需要执行的类名,和方法名 * @author zjq */ @Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)public @interface Pro { String className(); String methodName();}
通过解析注解配置,执行相关对象创建和执行对象方法。
获取注解定义的位置的对象 (Class,Method,Field)获取指定的注解调用注解中的抽象方法获取配置的属性值代码如下:
@Pro(className = "com.zjq.javabase.base25.annotation.Demo1",methodName = "show")public class ReflectTest { public static void main(String[] args) throws Exception { /** * 前提:不能改变该类的任何代码。可以创建任意类的对象,可以执行任意方法 */ //1.解析注解 //1.1获取该类的字节码文件对象 Class<ReflectTest> reflectTestClass = ReflectTest.class; //2.获取上边的注解对象 //其实就是在内存中生成了一个该注解接口的子类实现对象 /* public class ProImpl implements Pro{ public String className(){ return "com.zjq.javabase.base25.annotation.Demo1"; } public String methodName(){ return "show"; } } */ Pro an = reflectTestClass.getAnnotation(Pro.class); //3.调用注解对象中定义的抽象方法,获取返回值 String className = an.className(); String methodName = an.methodName(); System.out.println(className); System.out.println(methodName); //4.加载该类进内存 Class cls = Class.forName(className); //5.创建对象 Object obj = cls.newInstance(); //6.获取方法对象 Method method = cls.getMethod(methodName); //7.执行方法 method.invoke(obj); }}
案例:通过自定义注解定义一个简单的测试框架
定义一个测试注解
@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)public @interface Check {}
定义一个计算器工具类,并在方法上使用@Check注解
/** * 小明定义的计算器类 * @author zjq */public class Calculator { //加法 @Check public void add(){ String str = null; str.toString(); 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)); } public void show(){ System.out.println("永无bug..."); } }
定义测试框架类并执行测试,把测试异常记录到bug.txt文件中,代码如下:
/** * 简单的测试框架 * 当主方法执行后,会自动自行被检测的所有方法(加了Check注解的方法),判断方法是否有异常, * 记录到文件中 * * @author zjq */public class TestCheck { public static void main(String[] args) throws IOException { //1.创建计算器对象 Calculator c = new Calculator(); //2.获取字节码文件对象 Class cls = c.getClass(); //3.获取所有方法 Method[] methods = cls.getMethods(); int number = 0;//出现异常的次数 BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt")); for (Method method : methods) { //4.判断方法上是否有Check注解 if (method.isAnnotationPresent(Check.class)) { //5.有,执行 try { method.invoke(c); } catch (Exception e) { //6.捕获异常 //记录到文件中 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(); } }
执行测试后可以在src同级目录查看到bug.txt文件内容如下:
add 方法出异常了异常的名称:NullPointerException异常的原因:null--------------------------div 方法出异常了异常的名称:ArithmeticException异常的原因:/ by zero--------------------------本次测试一共出现 2 次异常
总结
1.大多数时候,我们只是使用注解,而不是自定义注解。
2.注解不是程序的一部分,可以理解为注解就是一个标签。
3.注解给谁用?
编译器
给解析程序用
到此这篇关于详解Java如何实现自定义注解的文章就介绍到这了,更多相关Java自定义注解内容请搜索盛行IT以前的文章或继续浏览下面的相关文章希望大家以后多多支持盛行IT!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。