1.注解
1.1.注解概述、作用
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
- 注解:说明程序的。给计算机看的
- 注释:用文字描述程序的。给程序员看的
对Java中类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来定。
例如:JUnit框架中,标记了注解@Test的方法就可以被当成测试方法执行,而没有标记的就不能当成测试方法执行
作用分类:
①编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
③编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】
1.2.内置注解
Java中有三种内置注解,这些注解用来为编译器提供指令,它们是:
@Deprecated
这个元素是用来标记过时的元素,编译器在编译阶段遇到这个注解时会发出提醒警告,告诉开发者正在调用一个过时的元素比如过时的方法、过时的类、过时的成员变量
可以用来标记类,方法,属性;
@Override
用来修饰对父类进行重写的方法。如果一个并非重写父类的方法使用这个注解,编译器将提示错误。
实际上在子类中重写父类或接口的方法,@Overide并不是必须的。但是还是建议使用这个注解,在某些情况下,假设你修改了父类的方法的名字,那么之前重写的子类方法将不再属于重写,如果没有@Overide,你将不会察觉到这个子类的方法。有了这个注解修饰,编译器则会提示你这些信息
@SuppressWarnings
用来抑制编译器生成警告信息
可以修饰的元素为类,方法,方法参数,属性,局部变量
当我们一个方法调用了弃用的方法或者进行不安全的类型转换,编译器会生成警告。我们可以为这个方法增加@SuppressWarnings注解,来抑制编译器生成警告。
注意:使用@SuppressWarnings注解,采用就近原则,比如一个方法出现警告,我们尽量使用@SuppressWarnings注解这个方法,而不是注解方法所在的类。虽然两个都能抑制编译器生成警告,但是范围越小越好,因为范围大了,不利于我们发现该类下其他方法的警告信息
//告诉编译器忽略 unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。
@SuppressWarnings(“unchecked”)//如果编译器出现这样的警告信息:The serializable class WmailCalendar does not declare a //static final serialVersionUID field of type long,使用这个注释将警告信息去掉。
@SuppressWarnings(“serial”)//如果使用了使用@Deprecated注释的方法,编译器将出现警告信息。使用这个注释将警告信息去掉。
@SuppressWarnings(“deprecation”)//rawtypes是说传参时也要传递带泛型的参数
@SuppressWarnings(“rawtypes”) //抑制所有类型的警告:
@SuppressWarnings(“all”)
2.元注解
元注解是指用于注解其他注解的注解。在Java中,元注解是一种特殊的注解,用于对其他注解进行修饰和控制。元注解可以用于定义自定义注解的行为、作用范围、生命周期等属性。
本质:注解本质上就是一个接口,该接口默认继承Annotation接口
* public interface MyAnno extends java.lang.annotation.Annotation {}
元注解有两个:
- @Target: 约束自定义注解只能在哪些地方使用,
- @Retention:申明注解的生命周期
@Target中可使用的值定义在ElementType枚举类中,常用值如下:
- TYPE,类,接口,枚举
- FIELD, 成员变量
- METHOD, 成员方法
- PARAMETER, 方法参数
- CONSTRUCTOR, 构造器
- LOCAL_VARIABLE, 局部变量
- ANNOTATION_TYPE:注解类型。
- PACKAGE:包。
@Retention中可使用的值定义在RetentionPolicy枚举类中,常用值如下:
- SOURCE: 注解只作用在源码阶段,生成的字节码文件中不存在
- CLASS: 注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值.
- RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)
@Documented:指定注解是否包含在Java文档中。
@Inherited:指定注解是否可以被继承。如果一个注解被@Inherited修饰,那么它将被子类继承。
@Repeatable:指定注解是否可重复应用于同一目标元素。该元注解在Java 8中引入。
元注解的作用是为其他注解提供更多的控制和限制。通过使用元注解,开发人员可以定义自己的注解,并指定它们的作用范围、生命周期和其他属性,从而实现更加灵活和可定制的注解功能。
3.自定义注解
自定义注解就是自己做一个注解来使用
- value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写!!
- 但是如果有多个属性, 且多个属性没有默认值,那么value名称是不能省略的。
4.注解解析
注解的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容
要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation对象
与注解解析相关的接口:
- Annotation: 注解的顶级接口,注解都是Annotation类型的对象
- AnnotatedElement:该接口定义了与注解解析相关的解析方法
解析注解的技巧:
注解在哪个成分上,我们就先拿哪个成分对象。
- 比如注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解
- 比如注解作用在类上,则要该类的Class对象,再来拿上面的注解
- 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解
5.案例
模拟Junit框架:定义若干个方法,只要加了MyTest注解,就可以在启动时被触发执行
public class Calculator {//加法@Checkpublic void add(){System.out.println("1 + 0 =" + (1 + 0));}//减法@Checkpublic void sub(){System.out.println("1 - 0 =" + (1 - 0));}//乘法@Checkpublic void mul(){System.out.println("1 * 0 =" + (1 * 0));}//除法@Checkpublic void div(){System.out.println("1 / 0 =" + (1 / 0));}public void show(){System.out.println("永无bug...");}
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Check {
}
public class TestCheck {/*** 简单的测试框架** 当主方法执行后,会自动自行被检测的所有方法(加了Check注解的方法),判断方法是否有异常,记录到文件中*/public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, IllegalAccessException, IOException {//Class cls = Class.forName("annotation.Calculator");Calculator c = new Calculator();Class<? extends Calculator> cls = c.getClass();//获取所有方法int number=0;//出现异常的次数BufferedWriter br=new BufferedWriter(new FileWriter("bug.txt"));Method[] methods = cls.getMethods();for (Method m :methods) {//判断方法上是否有check注释if(m.isAnnotationPresent(Check.class)){try {m.invoke(c);} catch (Exception e) {//捕获异常//记录到文件
number++;
br.write(m.getName()+"方法出异常了");
br.newLine();
br.write("异常名称"+e.getCause().getClass().getSimpleName());
br.newLine();
br.write("异常原因"+e.getCause().getMessage());}}}br.write("本次一共出现"+number+"次异常");br.flush();br.close();}
}