Java-注解

1|0概念

  • Jdk1.5之后引入注解概念
  • 用来说明,注释

2|0作用

  1. 编译检查
    如:@Override,检查方法是否继承父类
  2. 编写文档
    如:@author、@version、@since、@see、@link、@code、@param、@return、@exception、@throws等
  3. 代码分析
    使用反射对代码进行分析

3|0JDK内置注解

  • @Override:检查方法是否继承父类
  • @Deprecated:表示已过时
  • @SuppressWarnings:压制警告,标注此注解后就不提示警告了
    一般传递参数all:@SuppressWarnings("all")

案例:

//压制警告
@SuppressWarnings("all")
public class Demo {
/**
* 继承父类
* @return
*/
@Override
public String toString() {
return super.toString();
}
/**
* 已过时
*/
@Deprecated
public void show(){
//有缺陷
}
public void show2(){
}
public void tt(){
//show方法有删除线
show();
show2();
}
}

4|0自定义注解

格式:

  • 元注解
  • public @interface 注解名称 {
      属性列表
    }

本质:

  • 注解的本质就是接口,默认继承Annotation接口

属性:接口中的抽象方法

  1. 属性的返回值类型有下列取值
    基本数据类型
    String
    枚举
    注解
    以上类型的数组
  2. 定义了属性,在使用时需要给属性赋值
    如果使用属性时设置了default默认初始值,则使用注解时可以不进行属性赋值
    如果只有一个名为value的属性,使用注解时value可以省略,直接赋值即可
    数组赋值时,值使用{ }包裹,如果只有一个值,大括号可以省略

元注解:用于描述注解的注解

  • @Target:描述注解能够作用的位置
      ElementType的取值:
        TYPE:作用于类上
        FIELD:作用于成员变量上
        METHOD:作用于方法上
  • @Retention:描述注解能够保留的阶段
      RetentionPolicy的取值:
        SOURCE:当前被描述的注解,不会保留到class字节码文件中
        CLASS:当前被描述的注解,会保留到class字节码文件中,但不会被JVM读取到
        RUNTIME:当前被描述的注解,会保留到class字节码文件中,并被JVM读取到(自定义注解一般都使用RUNTIME)
  • @Documented:描述注解是否会被抽取到api文档中
  • @Inherited:描述注解是否被子类继承

5|0解析注解

在程序中使用(解析)注解:获取注解中定义的属性值

  • 获取注解定义位置(类,方法,成员变量)的对象
  • 获取指定的注解
      getAnnotation(自定义注解.class)
  • 调用注解中的抽象方法获取配置的属性值

案例:使用自定义注解,加载配置,并运行程序

  1. 创建类和方法待用
public class Prop1 {
public void show(){
System.out.println("pro1--show");
}
}
  1. 自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAn {
String className();
String methodName();
}
  1. 使用注解加载配置
//@MyAn(className = "类的路径",methodName = "方法名")
@MyAn(className = "com.annotation.Prop1",methodName = "show")
public class Test {
public static void main(String[] args) throws Exception {
//获取该类字节码文件对象
Class<Test> tc = Test.class;
//获取注解对象
//其实就是在内存中生成了一个该注解接口的子类实现对象
MyAn an = tc.getAnnotation(MyAn.class);
//获取注解对象中定义的抽象方法,获取返回值
String className = an.className();//类的路径
String methodName = an.methodName();//方法名
//加载该类进内存
Class<?> ac = Class.forName(className);
//创建类的对象
Object obj = ac.getDeclaredConstructor().newInstance();
//根据方法名,获取方法对象
Method method = ac.getMethod(methodName);
//调用方法
method.invoke(obj);
}
}
  1. 运行结果:
pro1--show

6|0练习

  1. 自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Check {
}
  1. 创建一个类,待测试
//一个计算器类
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("大秦万年……");
}
}
  1. 简易测试框架
/**
* 简易测试框架
* 1.当主方法执行后,会自动检测加了@Check的方法
* 2.判断方法是否有异常
* 3.将异常记录到文件中
*/
public class TestCheck {
public static void main(String[] args) throws IOException {
//创建计算器对象
Calculator cal = new Calculator();
//获取字节码文件对象
Class<? extends Calculator> ac = cal.getClass();
//获取所有成员方法
Method[] methods = ac.getDeclaredMethods();
//记录异常出现的次数
int count = 0;
//异常日志写入bug.txt
BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));
//遍历方法
for (Method method : methods) {
//判断方法上是否有@Check注解
if (method.isAnnotationPresent(Check.class)) {
try {
//如果有@Check注解,执行方法
method.invoke(cal);
} catch (Exception e) {
//捕获异常,记录文件信息
count++;//异常次数+1
bw.write(method.getName() + "出异常了");
bw.newLine();//换行
//getCause()异常原因,getSimpleName()简短名称
bw.write("异常的名称是:" + e.getCause().getClass().getSimpleName());
bw.newLine();
//getMessage()获取具体原因
bw.write("异常的原因是:" + e.getCause().getMessage());
bw.newLine();
bw.write("-----------------");
bw.newLine();
}
}
}
bw.write("本次测试共出现【"+count+"】次异常。");
//刷新流
bw.flush();
//关闭流
bw.close();
}
}
  1. 运行结果:加了@Check注解的方法,有3个运行正常
1+0=1
1-0=1
1*0=0
  1. 日志记录
div出异常了
异常的名称是:ArithmeticException
异常的原因是:/ by zero
-----------------
本次测试共出现【1】次异常。

7|0总结

  • 一般我们会使用注解,而不是自定义注解
  • 注解用在哪里?
      编译器
      给解析程序用
  • 注解不是程序的一部分,而是一个标签

8|0拓展

小贴士

  • 编译命令:javac **.java
  • 反编译命令:javap **.class
  • 生成api文档命令:Javadoc **.java
  • 接口中的方法都是抽象方法
  • 定义常量时,可以设置默认值:String name() default "abc"

枚举

  • 定义枚举时要使用Enum关键字;
  • 命名时类名尽量要带Enum , 常量全部大写,多个单词之间用_分割;
  • 枚举是一种特殊的常量类;
  • 默认的构造方法必须是私有的;
  • 枚举里的常量相当于枚举对象;
  • 常量之间用逗号分隔,用分号结尾。

__EOF__

本文作者茶碗儿
本文链接https://www.cnblogs.com/chawaner/p/17378831.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   茶碗儿  阅读(16)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
点击这里跳转到-->【茶碗儿CSDN】
点击右上角即可分享
微信分享提示