亲宝软件园·资讯

展开

Java注解 看这一篇就够了

yZzc_XQ 人气:1
# 注解 ## 1.概念 注解:说明程序的。给计算机看的 注释:用文字描述程序的。给程序员看的 注解的定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。 ## 2.作用 ①编写文档:通过代码里标识的注解生成文档【生成文档doc文档】: ​ shift+右键 -> 在此处打开Powershell窗口 -> 输入:javadoc .\类名.java ②代码分析:通过代码里标识的注解对代码进行分析【使用反射】 ③编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】 ## 3.Java 的三大注解 1.@Override:表明子类中覆盖了超类中的某个方法,如果写错了覆盖形式,编译器会报错 2.@deprecated:废弃的(过时的)表明不希望别人在以后使用这个类,方法,变量等. 3.@suppresswarnings:抑制警告 ​ 达到抑制编译器产生警告的目的,但是不很不建议使用,因为后期编码人员看不懂编译器 提示的警告,不能更好的选择更好的类去完成任务。 ​ 一般传递参数:all @SuppressWarnings("all") 可以加在类的上面一行,这样代码就 没有警告了,显得比较干净。 ## 4.自定义注解: 本质:注解本质上就是一个接口,该接口默认继承Annotation接口 ​ public interface MyAnno extends java.lang.annotation.Annotation {} ​ 可以在Powershell窗口反编译看看: ![](https://img2020.cnblogs.com/blog/1971784/202003/1971784-20200320101724210-2029190552.jpg) 格式: ```java public @interface 注解名称{ /* 属性列表; * 注解中的属性 主要定义抽象方法 不定义常量 * 抽象方法的返回值类型有要求(): * 1.基本数据类型 * 2.String * 3.枚举类型 * 4.注解 * 5.数组(以上几种类型的数组) */ } ``` ```java //属性列表中抽象方法的举例: public @interface MyAnno { int getName(); String getStr(); Season getSeason(); //新建Enum枚举类Season MyAnno2 getMyAnno2(); //新建Annotation注解类MyAnno2 String[] value(); //int getName() default 0; //如果不想为注解中的某个属性赋值,可以为其定义默认值 } ``` ```java //枚举类 public enum Season { SPRING,SUMMER,AUTUMN,WINtER } ``` 注解类定义了属性,那么在使用时必须给属性赋值。 ```java /* 1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。int getName() default 0; @MyAnno() public static void test02() {} 2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。 3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略。 */ //对我们自定义的MyAnno注解类的使用: @MyAnno(getName = 1, getStr = "100", getSeason = Season.SPRING, getMyAnno2= @MyAnno2,value = {"1","2"}) public static void test01() {} ``` 元注解:用于描述注解的注解(注解前面的注解) ```java @Target:描述注解能够作用的位置 ElementType取值: TYPE:可以作用于类上 FIELD:可以作用于成员变量上 METHOD:可以作用于方法上 @Retention:描述注解被保留的阶段 SOURCE: 源代码阶段, 被编译器忽略 CLASS: 注解将会被保留在Class文件中,但在运行时并不会被VM保留。这是默认行为,所有没 有用Retention注解的注解,都会采用这种策略。 RUNTIME:保留至运行时。所以我们可以通过反射去获取注解信息。 @Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到 //下面两个了解 @Documented:描述注解是否被抽取到api文档中 @Inherited:描述注解是否被子类继承 ``` 对Java的三大注解之一的SuppressWarnings注解进行分析: ```java @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); //只有一个属性,且名称为value,且为数组赋值 } @SuppressWarnings(value={"all"}) public class AnnoTest {} //同样可以这么使用 @SuppressWarnings({"all"}) //使用时可以省略value @SuppressWarnings("all") //使用时可以省略{} ``` ## 5.注解的使用 注解的作用:将我们为注解中的属性(抽象方法)赋的值提取出来,在类中使用 1. 获取注解定义的位置的对象 (Class,Field,Method) 2. 获取指定的注解: getAnnotation(Class annotationClass):方法返回该元素的指定类型的注释,如果是这样的注释,否则返回null ​ 参数:annotationClass -- 对应于注释类型的Class对象。 ## 6.案例 1.定义该类使用注解加反射,实现不修改任何代码(只需要修改注解中的值),就可以实现调用任意类中的任意方法 ```java //自定义注解类 @Retention(RUNTIME) @Target(TYPE) public @interface Pro { String className(); //通过该属性获取到类名 String methodName(); //通过该属性获取到方法名 } ``` ```java @SuppressWarnings("all") @Pro(className = "com.huike.b.useanno.Demo2", methodName = "show") public class AnnoTest { public static void main(String[] args) throws Exception { //1.解析注解 //1.1:获取加注解的类的字节码文件对象 //1.2:获取注解对象 Class cls = AnnoTest.class; //通过当前类的Class对象获取到类上的注解对象 Pro pro = (Pro) cls.getAnnotation(Pro.class); //2.调用注解中的抽象方法 获取到返回值 String className = pro.className(); String methodName = pro.methodName(); //3.获取到返回值所对应的类的Class对象 Class cls1 = Class.forName(className); //4.创建该类的对象 Object object = cls1.newInstance(); //5.获取到该类的特定方法对象 Method method = cls1.getMethod(methodName); //6.执行方法 method.invoke(object); } } ``` 2.测试框架: * 当main方法执行后,会自动执行被检测的所有方法(被加了Check注解的方法),判断方法内是否有异常 * 如果没有就算了,如果有异常,会自动记录到特定的文件中,文件中记录哪些方法出异常了,异常的名称是什么异常的原因是什么 * 得出总结:本次共测试了多少方法,出现了多少次异常 ```java //Check注解: @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface Check { } ``` ```java //自定义Calculator类,被用于测试 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..."); } } ``` ```java //测试类 public class CheckDemo { public static void main(String[] args) throws Exception{ //1.创建计算器对象 得到对应的Class对象 Calculator c = new Calculator(); Class cls = c.getClass(); //2.获取到该对象中的所有的方法 Method[] methods = cls.getDeclaredMethods(); int num01 = 0; //定义一个int类型的值用于记录出现的异常次数 int num02 = 0; //定义一个int类型的值用于记录带有Check注解的方法数 BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt")); //3.判断哪些方法上有Check注解 for (Method method : methods) { //该方法用于判断 方法上是否有特定的注解 //4.如果有Check注解,执行该方法 如果该方法无任何异常,就算了 if (method.isAnnotationPresent(Check.class)) { num02++; try { method.invoke(c); //如果有注解,则执行该方法 } catch (Exception e) { num01++; //5.如果有异常,记录异常信息,并通过IO流打印到文件中 //如果方法存在异常 需要在此通过IO流捕获 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("本次测试结束了,一共测试了"+num02+"个方法,共出现了"+num01+"次异常!"); bw.flush(); bw.close(); } } ```

加载全部内容

相关教程
猜你喜欢
用户评论