day22Java-注释和注解

博客
Java-(高级)

注释和注解概述
注解:注解就是符合一定格式的语法 @xxxx,说明程序的,给计算机看的。
注释:用文字描述程序的。给程序员看的

定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

概念描述:
		 JDK1.5之后的新特性
		 说明程序的
		 使用注解:@注解名称
		
作用分类:
		①编写文档:通过代码里标识的注解生成文档【生成文档doc文档】
		②代码分析:通过代码里标识的注解对代码进行分析【使用反射】
		③编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查【Override】

jdk5提供的注解
		@Override:告知编译器此方法是覆盖父类的
		@Deprecated:标注过时
		@SuppressWarnings:压制警告
自定义注解
格式:
			元注解
			public @interface 注解名称{
				属性列表;
			}

本质:注解本质上就是一个接口,该接口默认继承Annotation接口
自定义一个接口

public @interface MyAnno {
}

使用反编译工具查看
import java.lang.annotation.Annotation;
public interface MyAnno extends Annotation{
}

属性:接口中的抽象方法要满足
通过注解使用注解中的抽象方法,好像是给属性赋值,所以把抽象方法描述成属性。

	1. 属性的返回值类型有下列取值
		 基本数据类型
		 String
		 枚举
		 注解
		 以上类型的数组
	
	2. 定义了属性,在使用时需要给属性赋值
		1. 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
		2. 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
		3. 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略
  • 定义注解属性代码演示
public @interface MyAnno {
    //基本数据类型
    int show();
    //String
    String show2();
    //枚举
    Person per();
    //注解
    MyAnno2 myAnno();
    //以及上述类型的数组
    String[] strs();
}

Mynno2注解给Mynno做属性

public @interface MyAnno2 {
}

Person给Mynno做枚举类类型

public enum Person {
    p1,p2,p3
}
  • 使用注解属性代码演示
@MyAnno(value = 1,per = Person.p1,anno = @MyAnno2,name = "李四",strs = {"aaa","bbb"})
public class Work {
}

自定义注解MyAoon

public @interface MyAnno {
    //基本类型
    //int show();
    //如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
    int value();

    //枚举类型
    Person per();

    //注解类型
    MyAnno2 anno();

    //如果我不想给注解的该属性赋值,就是用default给一个默认值。
    String name() default "张三";

    //如果数组中只有一个值,可以省略大括号{}。
    String[] strs();
}

Mynno2注解给Mynno做属性

public @interface MyAnno2 {
}

Person给Mynno做枚举类类型

public enum Person {
    p1,p2,p3
}
元注解

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

@Target:描述注解能够作用的位置
		ElementType取值:
				TYPE:可以作用于类(接口)上
				METHOD:可以作用于方法上
				FIELD:可以作用于成员变量上
				PARAMETER:可以作于方法参数上
    			CONSTRUCTOR:可以作用于构造方法上
    			LOCAL_VARIABLE:可以作用与成员变量上
@Retention:描述注解被保留的阶段
		@Retention(RetentionPolicy.RUNTIME):注解在整个运行阶段都可见(自定义一般都是取该值)
		@Retention(RetentionPolicy.CLASS):注解在字节码文件级别可见
		@Retention(RetentionPolicy.SOURCE):注解在源码级别可见
@Documented:描述注解是否被抽取到api文档中(加上该注解,表示子注解可以在生成的文档中看到)
@Inherited:描述注解是否被子类继承(加上该注解,表是子注解标记的类的子类也可以继承子注解)

@Target:描述注解能够作用的位置
使用自定义注解

@MyAnno
public class Student {
    //@MyAnno 该注解只能定义在类上,所以报错
    public void getStudent(){}
}

自定义注解

@Target(ElementType.TYPE)//表示下面的注解只能定义在类上
public @interface MyAnno {
}

@Retention:描述注解被保留的阶段
SOURCE、CLASS、RUNTIME注解的保留阶段的图解。
在这里插入图片描述

@Documented:描述注解是否被抽取到api文档中
我自定义了两个注解,和一个实体类来测试
自定义MyAnno注解,加上@Documented注解,就可以在生成的API中查看到@MyAnno

@Target(ElementType.METHOD)
@Documented //表示下面的注解在生成API中可以看到
public @interface MyAnno {

}

自定义MyAnno2注解

@Target(ElementType.METHOD)
public @interface MyAnno2 {
    
}

实体类

public class Student {
    @MyAnno
    public void getStudent(){}
    @MyAnno2
    public void getStudent2(){}
}

上述三个方法一个文件中然后使用Javadoc 执行Student.java文件就可以看到生成的API文档
加上@Documented注解,就可以在生成的API中查看到@MyAnno
在这里插入图片描述
@Inherited:描述注解是否被子类继承
自定义注解

@Target(ElementType.TYPE)
@Inherited//加上该注解,表是子注解标记的类的子类也可以继承子注解
public @interface MyAnno {

}

子类Student

//因为子注解被@Inherited标记,就表示Person的注解@MyAnno被继承了过来
//就相当于@MyAnno
public class Student extends Person{

}

父类Person

@MyAnno
public class Person {

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

获取注解中定义的属性值测试

@MyAnno(className = "com.ginger.demo01.Student", methodName = "show")
public class MyAnnoTest {

    @Test
    public void testMyAnno() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //获取MyAnno注解对象
        //其实就是在内存中生成了一个该注解接口的子类实现对象
        /*public class MyAnnoImpl implements MyAnno{
            public String className(){
                return "cn.itcast.annotation.Demo1";
            }
            public String methodName(){
                return "show";
            }

        }
        */
        MyAnno myAnno = MyAnnoTest.class.getAnnotation(MyAnno.class);

        //根据MyAnno注解对象获取类名和方法名称
        String className = myAnno.className();
        String methodName = myAnno.methodName();
        //System.out.println(className);
        //System.out.println(methodName);

        //获取该类的字节码文件对象
        Class c = Class.forName(className);
        //通过无参创建学生对象
        Constructor cons = c.getConstructor();
        //创建对象
        Object obj = cons.newInstance();

        //获取方法对象
        Method mehtod = c.getMethod(methodName);
        //执行该方法
        mehtod.invoke(obj);
    }
}

自定义注解

@Target(ElementType.TYPE)//子注解只能作用在类上
@Retention(RetentionPolicy.RUNTIME)//注解在整个运行阶段都可见
public @interface MyAnno {
    String className();
    String methodName();
}

实体类

public class Student {
    public void show(){
        System.out.println("show....");
    }
}

结果:

className:com.ginger.demo01.Student
methodName:show
show方法执行了.....
案例:简单的测试框架

写一个框架,就是在计算机类中的方法只要被@Check标记,被标记的方法就要被测试,并给出测试异常名称和异常原因,以及异常次数并记录bug.txt文件中。

代码演示

public class CalculatorTest {
    @Test
    public void testCalculator() throws Exception {
        //通过字节码文件对象,获取该字节码文件对象中的所有的方法对象。
        Class c1 = CalCulator.class;
        Method[] methods = c1.getMethods();

        //通过无参构造创建对象
        Object obj = c1.getConstructor().newInstance();

        //定义一个统计变量,用于统计异常次数
        int number = 0;
        BufferedWriter bw = new BufferedWriter(new FileWriter("bug.txt"));

        //遍历方法对象数组
        for (Method method : methods) {
            //判断方法上的注解是否是@Check
            if (method.isAnnotationPresent(Check.class)) {
                try {
                    //有@Check注解方法,就执行该方法
                    method.invoke(obj);//执行的每一个计算类中的方法,可能会抛出异常
                } catch (Exception e) {
                    //System.out.println(e); reflect.InvocationTargetException   运行期异常
                    //System.out.println(e.getCause()); ArithmeticException: / by zero   编译器异常
            /*
                   这里不是很懂,InvocationTargetException对象调用getCause()方法就变成ArithmeticException对象了
                   通过查看InvocationTargetException类的getCause()源码。
                    private Throwable target;

                    public Throwable getCause() {
                         return target;
                   }

                   public InvocationTargetException(Throwable target, String s) {
                         super(s, null);
                         this.target = target;
                   }
                  通过查看源码,知道返回的是一个Throwable对象,Throwable是Error和Exception父类,通过我自己分析
                  构造传来的对象应该就是实际真正出错的原因,即ArithmeticException。
                */
                    //捕获异常
                    //抛出异常后统计变量做++
                    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();
    }
}

自定义注解

@Target(ElementType.METHOD)//注解只能作用在方法上
@Retention(RetentionPolicy.RUNTIME)//在整个运行阶段都可见
public @interface Check {
}

计算机类

/**
 * 计算器类
 */
public class CalCulator {

    //加法
    @Check
    public void add() {
        String str = null;
        str.toString();
        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...");
    }
}

结果:bug.txt文件内容

add 方法出现异常了
异常名称:NullPointerException
异常原因:null
------------------------
div 方法出现异常了
异常名称:ArithmeticException
异常原因:/ by zero
------------------------
本次测试一共出现 2 次异常
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值