注解的使用

https://blog.csdn.net/briblue/article/details/73824058

https://blog.csdn.net/javazejian/article/details/71860633

 

注解的定义及作用

注解可以理解为一个标签,给类或方法加标签。

官方的定义:注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响。

注解本质是一个继承了Annotation的特殊接口,其具体实现类是Java运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler的invoke方法。该方法会从memberValues这个Map中索引出对应的值。而memberValues的来源是Java常量池。

我的理解:注解就是给类、方法、属性打上一个标签。  这个标签如果不做其它处理,本身是没有任何作用的。  所有会有对应的处理代码,处理方式是通过反射获取注解属性及值,之后再按照我们的处理逻辑来舒勇。

编译阶段的注解,编译器读到注解,则进行相应的处理。
spring的注解,在加载时spring使用反射读到注解,进行相应的操作,如自动注入。

处理 Annotation 的代码统称为 APT(Annotation Processing Tool)

 

注解的基本知识和语法

定义注解使用@interface定义,其本身也类似于一个接口。

元注解,即用来定义注解的注解,给这个注解打上标签。

元标签有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。

@Retention

    RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
    RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
    RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它

@Target

    ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
    ElementType.CONSTRUCTOR 可以给构造方法进行注解
    ElementType.FIELD 可以给属性进行注解
    ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
    ElementType.METHOD 可以给方法进行注解
    ElementType.PACKAGE 可以给一个包进行注解
    ElementType.PARAMETER 可以给一个方法内的参数进行注解
    ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

@Inherited

    可以被继承,子类自动继承父类的标签。

@Repeatable

     可以重复,同一个地方可以加多个相同的标签

//定义一个注解

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface PiaoQian {
	int value1() default 0;
	String[] value2() default {"a","b"};
	int value3();   //如果没有指定默认值,则在使用该注解时比如指定值
        public int value4();  //一般不写这个public 可以这其实是一个(类似于)方法,如同接口类
}

注解的属性

注解只有成员变量,没有方法。

以“无形参的方法”形式来声明,方法名定义变量名字,返回值定义变量类型。

定义属性时它的类型必须是 8 种基本数据类型外加 类、接口、注解  以及它们的数组。

 

以上就是注解的基本概念


怎么在代码中提取出注解

通过反射的方式去处理,Class、Method 、Field类中包含对注解的处理。

@TestAnnotation(msg="hello")
public class Test {
	
    @Check(value="hi")
    int a;
	
	
    @Perform
    public void testMethod(){}
	
	
    @SuppressWarnings("deprecation")
    public void test1(){

    }


    public static void main(String[] args) throws Exception {
	
        //判断此类中是否包含@TestAnnotation注解
	boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class);
		
	if ( hasAnnotation ) {
            //获取到该注解
	    TestAnnotation aat = Test.class.getAnnotation(TestAnnotation.class);
	    ///输出注解的内容,和调用成员变量的方式语法一样
	    System.out.println(aat.id());
	    System.out.println(aat.msg());
	}
		
	
	Field a = Test.class.getDeclaredField("a");
	a.setAccessible(true);  //关闭安全检查,提高效率
	//获取一个成员变量上的注解
	Check check = a.getAnnotation(Check.class);
	if ( check != null ) {
	    System.out.println(check.value());
	}
	
	
	Method testMethod = Test.class.getDeclaredMethod("testMethod");
	if ( testMethod != null ) {
	     // 获取方法上的所有注解
	     Annotation[] ans = testMethod.getAnnotations();
	     for( int i = 0;i < ans.length;i++) {
	        System.out.println(ans[i].annotationType().getSimpleName());
	     }
	}

		
    }

}

注解的实际作用及用法

当开发者使用了Annotation 修饰了类、方法、Field 等成员之后,这些 Annotation 不会自己生效,必须由开发者提供相应的代码来提取并处理 Annotation 信息。这些处理提取和处理 Annotation 的代码统称为 APT(Annotation Processing Tool)。
 

写一个测试框架,测试程序员的代码有无明显的异常。

—— 程序员 A : 我写了一个类,它的名字叫做 NoBug,因为它所有的方法都没有错误。
—— 我:自信是好事,不过为了防止意外,让我测试一下如何?
—— 程序员 A: 怎么测试?
—— 我:把你写的代码的方法都加上 @Jiecha 这个注解就好了。
—— 程序员 A: 好的。

package ceshi;
import ceshi.Jiecha;


public class NoBug {
	
	@Jiecha
	public void suanShu(){
		System.out.println("1234567890");
	}
	@Jiecha
	public void jiafa(){
		System.out.println("1+1="+1+1);
	}
	@Jiecha
	public void jiefa(){
		System.out.println("1-1="+(1-1));
	}
	@Jiecha
	public void chengfa(){
		System.out.println("3 x 5="+ 3*5);
	}
	@Jiecha
	public void chufa(){
		System.out.println("6 / 0="+ 6 / 0);
	}
	
	public void ziwojieshao(){
		System.out.println("我写的程序没有 bug!");
	}

}

上面的代码,有些方法上面运用了 @Jiecha 注解。

这个注解是我写的测试软件框架中定义的注解。

package ceshi;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface Jiecha {

}

然后,我再编写一个测试类 TestTool 就可以测试 NoBug 相应的方法了。

package ceshi;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestTool {

    public static void main(String[] args) {
        // TODO Auto-generated method stub

	NoBug testobj = new NoBug();

	Class clazz = testobj.getClass();

	Method[] method = clazz.getDeclaredMethods();
	// 用来记录测试产生的 log 信息
	StringBuilder log = new StringBuilder();
	// 记录异常的次数
	int errornum = 0;

	for (Method m : method) {
	    // 只有被 @Jiecha 标注过的方法才进行测试
	    if (m.isAnnotationPresent(Jiecha.class)) {
		try {
	            m.setAccessible(true);
		    m.invoke(testobj, null);

		} catch (Exception e) {
		    errornum++;
		    log.append(m.getName());
		    log.append(" ");
		    log.append("has error:");
		    log.append("\n\r  caused by ");
		    log.append(e.getCause().getClass().getSimpleName());
		    log.append("\n\r");
		    // 记录测试过程中,发生的异常的具体信息
		    log.append(e.getCause().getMessage());
		    log.append("\n\r");
		}
	    }
	}

	log.append(clazz.getSimpleName());
	log.append(" has  ");
	log.append(errornum);
	log.append(" error.");
	// 生成测试报告
	System.out.println(log.toString());

    }

}

提示 NoBug 类中的 chufa() 这个方法有异常,这个异常名称叫做 ArithmeticException,原因是运算过程中进行了除 0 的操作。

所以,NoBug 这个类有 Bug。

这样,通过注解我完成了我自己的目的,那就是对别人的代码进行测试。

所以,再问我注解什么时候用?我只能告诉你,这取决于你想利用它干什么用。
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值