一、注释
用文字描述程序,给程序员看的。
二、注解
说明程序的,给计算机看的。
定义:Annotation,也叫元数据,一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明注释。
概念描述:
(1)JDK1.5之后的新特性
(2)说明程序的
(3)使用注解:@注解名称
作用分类:
(1)编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查(Override)
(2)编写文档:通过代码里标识的元数据生成文档(生成文档doc文档)
(3)代码分析:通过代码里标识的元数据对代码进行分析(使用反射)
三、有关注释的学习
(一)JDK中预定义的一些注解:
- @Override:检测被该注解标注的方法是否是继承自父类(接口),如果是则编译;否则不编译
- @Deprecated:该注解标注的内容,已过时(也可使用)
- @SuppressWarnings:压制警告
一般传递参数all:@SuppressWarnings(“all”)
(二)自定义注解
- 格式:
a、元注解
b、public @interface 注解名称() { 属性列表; }
- 本质:注解就是一个接口,该接口默认继承Annotation接口
pubic interface MyAnno extends java.lang.annotation.Annotation {
}
- 属性:接口中可以定义的属性
(1)要求:
a、属性的返回值类型(无void)
· 基本数据类型
· String
· 枚举
· 注解
· 以上类型的数组
public @interface MyAnno {
int age();
String name();
Person per();
MyAnno2 anno2();
String[] str();
}
public enum Person {
P1,P2;
}
public @interface MyAnno2 {
}
b、定义了属性时,需要给属性赋值
//引用上述注释可得
@MyAnno(age = 20, name="moon" , per=Person.P1 , anno2 = @MyAnno2 , str = {"abc","bbb"})
public class Worker {
}
· 如果定义属性时,使用default关键字给属性默认初始化,则使用注解时,可以不进行属性的赋值
public @interface MyAnno {
int value();
String name() default "moon";
}
· 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值可以
public @interface MyAnno {
int value();
}
@MyAnno(20)
public class Worker {
}
· 数组赋值时,值使用{}包裹,如果数组只有一个值,则{}可以省略
public @interface MyAnno {
int value();
String[] str();
}
@MyAnno(value = 20 , str = {"abc","bbb"})
或
@MyAnno(value = 20 , str = "abc")
public class Worker {
}
c、元注解:用于表述注解的注解
@Target:描述注解能够作用的位置
/*
* ElementType取值:
* TYPE:可以作用于类上
* METHOD:可以作用于方法上
* FIELD:可以作用于成员变量上
*
*/
@Target(value = {ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
public @interface MyAnno3 {
}
@Retention:面熟注解被保留的阶段
//当前被描述的注解,会保留到class字节码文件里,并被JVM读取到
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno3 {
}
@Documented:描述注解是否被抽取到api文档中
@Inherited:描述注解是否被子类继承
(三)在程序中使用(解析)注解(敲重点)
package domain;
public class Student {
public void sleep() {
System.out.println("睡得好香zzzzz...");
}
}
package Annotation;
/*
* 描述需要执行的类名和方法名
* */
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 domain1 {
String className();
String methodName();
}
package Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
@domain1(className = "domain.Student",methodName = "sleep")
public class ReflectTest {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException, NoSuchMethodException {
//1、获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass=ReflectTest.class;
//2、获取上方注解对象(指定)
domain1 an=reflectTestClass.getAnnotation(domain1.class);//其实就是在内存中生成一个该注释接口的子类实现对象
//3、调用注解对象中定义的抽象方法,获取返回值
String className=an.className();
String methodName=an.methodName();
//4、加载该类进内存
Class cla=Class.forName(className);
//5、创建对象
Object obj=cla.newInstance();
//6、获取方法对象
Method method=cla.getMethod(methodName);
//7、执行方法
method.invoke(obj);
}
}
四、案例:简易计算测试框架
package Annotation.demo;
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 {
}
package Annotation.demo;
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));
}
public void show() {
System.out.println("永无bug(扎心的词)...");
}
}
package Annotation.demo;
/*
* 简单测试框架
*
* 当主方法执行后,会自动自行被检测的所有方法(加了Check注解的方法),判断方法是否有异常
* 然后记录到文件中
* */
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class TestCheck {
public static void main(String[] args) throws IOException {
//1、创建计算器对象
Calculator c=new Calculator();
//2、获取字节码文件对象
Class cla=c.getClass();
//3、获取所有方法
Method[] methods=cla.getMethods();
int num=0;
BufferedWriter bw=new BufferedWriter(new FileWriter("bug.txt"));
//4、isAnnotationPresent判断方法是否有Check注释
for (Method method:methods) {
//5、判断是否有注解
if (method.isAnnotationPresent(Check.class)) {
try {
method.invoke(c);
} catch (Exception e) {
//捕获异常并记录到文件中
num++;
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("本次测试共出现"+num+"次异常");
bw.flush();
bw.close();
}
}
最终结果:
以及最后总结一个IDEA撤销上一步操作的方法:Ctrl+z