Java-Annotation
注解
-
概念:说明程序的,给计算机看的
-
注释:用文字描述程序的,给程序员看的
-
定义:注解(Annotation)也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与接口,类,枚举是在同一个层次,它可以声明在包、类、字段、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
-
概念描述:
-
JDK1.5之后的新特性
-
说明程序的
-
使用注解: @注解名称
-
作用分类:
①编写文档:通过代码里标识的注解生成文档(生成文档doc文档)
②代码分析:通过代码里标识的注解对代码进行分析(使用反射)
③编译检查:通过代码里标识的注解让编译器能够实现金币的编译检查(Override)
-
JDK中预定义的一些注解
- @Override:检测被该注解标注的方法是否继承父类(接口)的
- @Deprecated:该注解标识的内容, 表示已过时
- @SupperssWarnings:压制警告的
- 一般传递参数all @SuppressWarnings("all")
代码实现
package com.levizhao.demo01.annotation;
/*
JDK中预定义的一些注解
* @Override:检测被该注解标注的方法是否继承父类(接口)的
* @Deprecated:该注解标识的内容,表示已过时
* @SuppressWarnings: 压制警告
*/
@SuppressWarnings("all") //压制警告 需要传参 例如:all
public class Demo02Annotation {
@Override //检测被该注解标注的方法是否继承父类(接口)的
public String toString() {
return super.toString();
}
@Deprecated //该注解标识的内容,表示已过时
public void show1(){
//有缺陷
}
public void show2(){
//代替show1方法
}
public void demo(){
show1(); //在IDEA中会有该方法已过时
}
public void myzz(){
}
}
-
自定义注解
-
格式:
元注解public @interface 注解名称{ 属性列表; }代码如下:
public @interface myAnnot { //字符串类型 public abstract String show(); //int 类型 int show2(); //枚举类型 Testenum testenum(); //注解类型 myAnnot2 ma(); //字符串数组类型 String[] strs();枚举代码:
Testenum.java public enum Testenum { T1,T2; } -
本质:
注解的本质上就是一个接口,该接口默认继承Annotation接口
public interface MyAnno extends java.lang.annotation.Annotation{}javap mytest.class //反编译java代码 -
属性:
接口中可以定义的成员方法
-
要求:
- 属性的返回值类型
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型的数组
2.定义了属性,在使用时需要给属性赋值
1.如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值
2.如果值有一个属性需要赋值,并且属性的名称是value, 则value可以省略,直接定义值即可
3.数组赋值时,值使用{}包裹,如果数组中只有一个值,则{}省略
@myAnnot(show = "show",show2 = 2021,testenum = Testenum.T1,ma= @myAnnot2,strs = {"aaa","bbb","ccc"}) public class TestAnnot { } - 属性的返回值类型
-
-
元注解:用于描述注解的注解
-
@Target:描述注解能够作用的位置
-
ElementType取值:
*TYPE:可以作用于类上
*METHOD:可以作用于方法上
*FIELD:可以作用于成员变量上
-
-
@Retention:描述注解被保留的阶段
- Retention(RetentionPolicy.RUNTIME):当前被描述的注解,会保留到class字节码文件中,并被JVM读取到
-
@Documented: 描述注解是否被抽取到api文档中
- 使用javadoc 编译.java文件会被抽取到文档中
-
@Inherited:描述注解是否被子类继承
代码实例
package com.levizhao.demo02.annotation; /* 元注解:用于描述注解的注解 @Target:描述注解能够作用的位置 @Retention:描述注解被保留的阶段 @Documented:描述注解是否被抽取到api文档中 @Inherited:描述注解是否被子类继承 */ import java.lang.annotation.*; //ElementType.TYPE:表示该MyAnno3注解只能作用于类上 //ElementType.METHOD:表示注解用于方法上 //ElementType.FIELD:用于成员变量上 @Target(value={ElementType.TYPE,ElementType.METHOD,ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited public @interface MyAnno { } -
-
-
在程序使用(解析)注解:获取注解中定义的属性值
1.获取注解定义的位置的对象(Class,Method,Field)
2.获取指定的注解
getAnnotation(Class)
//其实就是在内存中生成一个该注解接口的子类实现对象
public String className(){
return "com.levizhao.demo03.annotation.Demo01"
}
public String methodName(){
return "show01" public class ProImpl implements Pro{
}
}
3.调用注解中的抽象方法获取配置的属性值
代码实例
//先创建测试类 Demo01.java
package com.levizhao.demo03.annotation;
public class Demo01 {
//定义show01方法
public void show01(){
System.out.println("Demo01的show01方法");
}
}
//创建注解
package com.levizhao.demo03.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 Pro {
String className();
String methodName();
}
/*
public class ProImpl implements Pro{
public String className(){
return "com.levizhao.demo03.annotation.Demo01"
}
public String methodName(){
return "show01"
}
}
*/
package com.levizhao.demo03.annotation;
/*
框架类
*/
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
//在这里获取注解定义的位置对象
@Pro(className = "com.levizhao.demo03.annotation.Demo01",methodName = "show01")
public class ReflectTest {
public static void main(String[] args) throws Exception {
/*
前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法
*/
//1.解析注解
//1.1获取该类的字节码文件对象
Class<ReflectTest> reflectTestClass = ReflectTest.class;
//2.获取上边的注解对象
//其实就是在内存中生成一个该注解接口的子类实现对象
/*
public String className(){
return "com.levizhao.demo03.annotation.Demo01"
}
public String methodName(){
return "show01" public class ProImpl implements Pro{
}
}
*/
Pro annotation = reflectTestClass.getAnnotation(Pro.class);
//3.调用注解对象中定义的抽象方法,获取返回值
String clasName = annotation.className();
String methodName = annotation.methodName();
System.out.println(clasName);
System.out.println(methodName);
//4.加载该类进内存
Class<?> aClass = Class.forName(clasName);
//5.创建对象
Object o = aClass.newInstance();
//6.获取方法对象
Method method = aClass.getMethod(methodName);
//执行方法
method.invoke(o);
}
}
- 小结:
- 以后大多数时候,我们会使用注解,而不是自定义注解
- 注解给谁用:
- 编译器
- 解析程序用
- 注解不是程序的一部分,可以理解为注解就是一个标签
注解的应用案例
/* 简单的测试框架 当主方法执行后,会自动自行被检测的所有方法(加了Check注解的方法),判断方法是否有异常,记录到文件中 /
定义一个计算器类- Calculator.java
package com.levizhao.demo04.annotation;
/**
* 定义计算器类
*/
public class Calculator {
//bug
@Check
public void bug(){
String a = null;
a.toString();
}
//加法
@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("Never bug....");
}
}
注解-Check.java
package com.levizhao.demo04.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}
测试Calculator.java函数- TestCheck.java
package com.levizhao.demo04.annotation;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
/**
* 简单的测试框架
*
* 当主方法执行后,会自动自行被检测的所有方法(加了Check注解的方法),判断方法是否有异常,记录到文件中
*/
public class TestCheck {
public static void main(String[] args) throws IOException {
//1.创建计算器对象
Calculator c = new Calculator();
//2.获取字节码文件对象
Class aClass = c.getClass();
//累加器 用于统计bug的个数
int num = 0;
//用于保存输出bug的日志
BufferedWriter bw = new BufferedWriter(new FileWriter("BugLogs.txt"));
//3.获取所有Method方法
Method[] methods = aClass.getMethods();
//4.遍历所有获取到的Method方法
for (Method method : methods) {
//5.判断方法上是否有Check注解
if (method.isAnnotationPresent(Check.class)){
//6.有 就执行
try {
method.invoke(c); // c是要执行类Calculator的实例化对象
} catch (Exception e) {
//7.捕获异常
//记录到文件中去
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();
}
}
输出结果:
[bug]方法出现异常了 异常的名称:NullPointerException 异常的原因:null -------------------------------------------------- [div]方法出现异常了 异常的名称:ArithmeticException 异常的原因:/ by zero -------------------------------------------------- 本次测试一共出现2次异常

浙公网安备 33010602011771号