注解
- JDK中预定义的注解
- 自定义注解
- 演示
- 元注解: 描述注解的注解
- 在程序中使用(解析)注解:获取注解中定义的属性值
- 简单的测试框架
JDK中预定义的注解
@override: 检测被注解标注的方法是否继承至父类(接口)的
@Deprecated:该注解标注的内容表示已过时
@SuppressWarnings:压制警告
//压制当前类可能弹出的所有警告被压制
@SuppressWarnings("all")
public class stu
{
String name;
//当前方法的所有警告被压制
@SuppressWarnings("all")
public void show()
{
System.out.println("学生的姓名:"+name);
}
}
自定义注解
格式:
元注解
public @interface 注解名称()
{
属性列表;
}
本质: 注解本质是一个接口,该接口默认继承Annotation接口
属性: 接口中的抽象方法
要求:
属性的返回类型由以下取值:
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型的数组
定义了属性,在使用时需要给属性赋值
- 如果定义属性时,使用default关键字给默认初始化值,则使用注解时,可以不进行属性的赋值
- 如果只有一个属性需要赋值,并且属性的名称叫value,则value可以省略,直接定义值即可
- 数组赋值时,值使用{}包裹,如果数组中只有一个值,{}可以省略
演示
自定义注解类:
package reflect;
public @interface annto {
int age();
String name();
Per p();
ann2 anno2();
String[] strs();
}
stu类:
package reflect;
@annto(age=18,name="大忽悠",p=Per.perople,anno2=@ann2,strs={"大忽悠","小朋友"})
public class stu
{
String name;
public void show()
{
System.out.println("学生的姓名:"+name);
}
}
元注解: 描述注解的注解
@Target :描述注解能够作用的位置
ElementType取值:
- TYPE: 可以作用于类上
- METHOD: 可以作用于方法上
- FIELD:可以作用于成员变量上
//value可以省略,下面的写法可以同时作用于类上,方法上,成员变量上
@Target({ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
//@Target(value={ElementType.TYPE,ElementType.METHOD,ElementType.FIELD})
public @interface ann2 {
}
@Retention:描述注解被保留的阶段
//当前被描述的注解,会被保留到字节码文件中,并被JVM读取到
@Retention(RetentionPolicy.RUNTIME)
@Documented:描述注解是否被抽取到api文档中
@Inherited:描述注解是否被子类继承’
@Inherited
public @interface ann2 {
}
下面使用ann2注解的类或者成员方法,其子类也会带上ann2注解
在程序中使用(解析)注解:获取注解中定义的属性值
获取注解定义位置的对象(Class , Method ,Field)
获取指定注解
getAnnotation(class)
//其实就是在内存中生成一个该注解接口的子类实现对象
public class ProImp1 implements ann2
{
public String ClassName()
{
return "reflect.stu";
}
public String MethodName()
{
return "show";
}
}
调用注解中的抽象方法,获取配置的属性值
演示:
需求: 不改变类的任意代码,创建类的任意对象,执行类的任意方法
ann2注解类:
package reflect;
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 ann2
{
String ClassName();
String MethodName();
}
stu类:
package reflect;
public class stu
{
String name;
public void show()
{
System.out.println("学生的姓名:"+name);
}
}
main函数:
package reflect;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
@ann2(ClassName = "reflect.stu",MethodName = "show")
public class main {
public static void main(String[] args) throws Exception
{
//1.获取该类的字节码文件对象
Class<main> mainClass=main.class;
//2.获取上面的注解对象
ann2 a2=mainClass.getAnnotation(ann2.class);
//其实就是在内存中生成一个该注解接口的子类实现对象
/* public class ProImp1 implements ann2
{
public String ClassName()
{
return "reflect.stu";
}
public String MethodName()
{
return "show";
}
}*/
//3.调用注解对象中定义的抽象方法,获取返回值
String className=a2.ClassName();
String methodName=a2.MethodName();
//3.加载该类进内存
Class cls=Class.forName(className);
//4.创建对象
Object obj=cls.newInstance();
//5.获取方法对象
Method method=cls.getMethod(methodName);
//6.执行方法
method.invoke(obj);
}
}
简单的测试框架
main:
package reflect;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
/*
* 当主方法执行后,会自动去执行所有被检测的方法(加了check注解的方法),如果方法有异常,那么将异常记录到文件中
* */
public class checkTest {
public static void main(String[] args) throws IOException {
//1.创建计算机对象
calculator c=new calculator();
//2.获取字节码文件对象
Class cls=c.getClass();
//3.获取所有方法
Method[] methods=cls.getDeclaredMethods();
//记录异常出现的次数
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();
}
}
calculator:
package reflect;
public class calculator {
@check
public void add()
{
System.out.println("a+b=大忽悠");
}
@check
public void minus()
{
System.out.println("1/0="+1/0);
}
@check
public void div()
{
String str=null;
str.toString();
}
}
check:
package reflect;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/*需要在自定义注解上加 @Retention(RetentionPolicy.RUNTIME),声明该注解的存活策略可以保留到运行时,再通过反射获取时才可以正确获取。*/
@Retention(RetentionPolicy.RUNTIME)
public @interface check {
}
测试结果:
bug.txt:
minus方法出异常了
异常的名称:ArithmeticException
异常的原因/ by zero
------------------------------------------
div方法出异常了
异常的名称:NullPointerException
异常的原因Cannot invoke "String.toString()" because "str" is null
------------------------------------------
本次测试一共出现2次异常