Java-注解
1、定义
对比
注解:说明程序的,给计算机看的
注释:用文字描述的,给程序员看的
定义:注解(Anotation)也叫元数据,一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释
定义描述
- JDK1.5后的新特性
- 用来说明程序的
- 使用注解:@注解名称
2、作用
- 编写文档:通过代码里标识的注解生成文档【生成doc文档】
- 代码分析:通过代码里标识的注解对代码进行分析【使用反射】
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【如Override】
3、JDK中预定义的注解
- @Override:检测被该注解标注的方法是否是继承自父类(接口)的
- @Deprecated:表示该注解标注的内容已经过时
- @SuppressWarnings:压制警告
- 一般传递参数all,@SuppressWarnings(“all”)表示压制所有警告
4、自定义注解
- 格式:
- 元注解
- public @interface 接口名{}
- 本质:注解本质上就是一个接口,该接口默认继承Annotation接口
- 原型:public interface MyAnno extends java.lang.annotation.Annotation{}
- 属性:接口中的抽象方法
- 属性的返回值有以下要求:
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型的数组
- 定义了属性,在使用时需要给属性赋值
- 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值
- 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
- 数组赋值时,值使用{}包裹,如果数组中只有一个值,则{}省略
- 属性的返回值有以下要求:
//自定义注解
package com.first;
public @interface MyAnno {
int age();
String name();
}
//使用注解
package com.first;
@MyAnno(age = 13, name = "cyh")
public class UseMyAnno {
}
5、元注解
所谓元注解就是注解上的注解,其本身也是一种注解,一种作用于其他注解的注解
- @Target:描述注解能够作用的位置
- ElementType取值
- TYPE:可以作用于类上
- METHOD:可以作用于方法上
- FIELD:可以作用于成员变量上
- ElementType取值
- @Retention:描述注解被保留的阶段
- @Retention(RetentionPolicy.RUMTIME):当前被描述的注解,会被保留到class字节码文件中,并被JVM读取到
- @Retention(RetentionPolicy.CLASS):当前被描述的注解,会被保留到class字节码文件中,当不会被JVM读取到
- @Retention(RetentionPolicy.SOURCE):当前被描述的注解,不会被保留到class字节码文件中
- @Documented:描述注解是否被抽取到API文档中
- @Inherited:描述注解是否被子类继承
6、使用(解析)注解
所谓解析注解,就是在程序中获取注解中定义的属性值
使用步骤:
- 获取注解定义的位置的对象(CLASS,METHOD,FIELD)
- 注解定义在类上:类名.class获取其字节码对象
- 注解定义在方法上:先获取方法所在类的字节码文件,再对此字节码文件用getMethod()即可得到这个方法的对象
- 获取指定的注解
- Class.getAnnotation(Class)
- Method.getAnnotation(Class)
- 调用注解中的抽象方法获取配置的属性值
package com.first;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
@ReflectAnno(className = "com.domain.Person", methodName = "eat")
public class ReflectByAnnoTest {
public static void main(String[] args) throws Exception{
//解析类上注解
//1获取该类的字节码文件对象
Class<ReflectByAnnoTest> reflectByAnnoClass = ReflectByAnnoTest.class;
//2.获取该类上边的某一注解的对象
ReflectAnno relAnno = reflectByAnnoClass.getAnnotation(ReflectAnno.class);
//3.调用注解对象中定义的抽象方法,获取返回值
String className = relAnno.className();
String methodName = relAnno.methodName();
//通过注解中classname定义的类名加载其字节码文件
Class<?> aClass = Class.forName(className);
//创建一个该类的对象
Constructor<?> constructor = aClass.getConstructor();
Object o = constructor.newInstance();
//获取注解中的方法
Method method = aClass.getMethod(methodName);
//调用该对象的方法
method.invoke(o);
}
@MyAnno(age = 11, name = "cuyj")
public static void test() throws NoSuchMethodException {
//解析方法上的注解
//1.获取方法所在类的对象
Class<ReflectByAnnoTest> reflectByAnnoClass = ReflectByAnnoTest.class;
//2.通过所在类的字节码文件获取到自己这个方法的对象
Method method = reflectByAnnoClass.getMethod("test");
//3.通过方法对象获取方法上的某个注解的对象
MyAnno myAnno = method.getAnnotation(MyAnno.class);
//4.调用注解中定义的方法
System.out.println(myAnno.name());
System.out.println(myAnno.age());
}
}
7、小结
- 以后大多数时候,我们会使用注解,而不是自定义注解
- 注解给谁用?
- 编译器:编译检查
- 给解析程序用:测试框架(如下)
- 注解不是程序的一部分,可以理解为注解就是一个标签
注解就是一个标签,告诉负责解析的程序(如测试框架)这个地方需要进行解析测试
Calculator类
package com.first;
import com.test.Check;
public class Calculator {
//@Check
public int add(int a, int b) {
return a + b;
}
//@Check
public int sub(int a, int b) {
return a - b;
}
@Check
public void div() {
System.out.println(2 / 0);
}
@Check
public void show() {
String s = null;
s.toString();
}
}
测试(解析)程序
package com.test;
import com.first.Calculator;
import javax.swing.*;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Method;
public class TestCheck {
public static void main(String[] args) throws IOException {
//1.创建计算器对象
Calculator c = new Calculator();
//2.获取字节码文件
Class cls = c.getClass();
//3.获取所有方法
Method[] methods = cls.getMethods();
int num = 0;//出现异常的次数
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
for (Method method : methods) {
if(method.isAnnotationPresent(Check.class)){//如果该方法上存在Check注解
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();
}
}
输出结果bug.txt
div方法出异常了
异常的原因ArithmeticException
异常的信息/ by zero
===================
show方法出异常了
异常的原因NullPointerException
异常的信息null
===================
本次测试一共出现2次异常
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 Ken·勇者の小栈
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果