• Java Annotation自定义注解详解


    在开发过程中总能用到注解,但是从来没有自己定义过注解。最近赋闲在家,研究整理了一番,力求知其然知其所以然。

    本文会尝试描述什么是注解,以及通过一个Demo来说明如何在程序中自定义注解。Demo没有实际意义,仅仅只是为了注解而使用注解。

     

    1、什么是注解?

           注解是在jdk 1.5开始提供的功能,目前被广泛使用。以下是引用《Java疯狂讲义》第十四章关于注解的描述:

           “Annotation其实是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行响应的处理。通过使用Annotation,程序开发人员可以在不改变原有逻辑的情况下,在源文件嵌入一些补充信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证或者进行部署。”

          

           JUnit单元测试就是基于注解的。我认为使用动态代理和注解,自己完全也可以写一个MyJUnit。

          

    2、Demo的实现:

    注解文件:

    这个文件主要包含了三个部分:

           A.注解文件使用@interface来声明。

           B.在A外层有元注解声明(注解的注解),主要的作用就是对我们自定义注解的执行范围、时期进声明。下面是注解的注解含义说明:

    @Documented:指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。应使用此类型来注释这些类型的声明:其注释会影响由其客户端注释的元素的使用。如果类型声明是用 Documented 来注释的,则其注释将成为注释元素的公共 API 的一部分。

    @Target:指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。例如,此元注释指示该声明类型是其自身,即元注释类型。它只能用在注释类型声明上。

    @Inherited:指示注释类型被自动继承。如果在注释类型声明中存在 Inherited 元注释,并且用户在某一类声明中查询该注释类型,同时该类声明中没有此类型的注释,则将在该类的超类中自动查询该注释类型。此过程会重复进行,直到找到此类型的注释或到达了该类层次结构的顶层 (Object) 为止。如果没有超类具有该类型的注释,则查询将指示当前类没有这样的注释。注意,如果使用注释类型注释类以外的任何事物,此元注释类型都是无效的。还要注意,此元注释仅促成从超类继承注释;对已实现接口的注释无效。

    @Retention:指示注释类型的注释要保留多久。如果注释类型声明中不存在 Retention 注释,则保留策略默认为 RetentionPolicy.CLASS。

    C.方法名就是参数名,返回值类型就是参数的类型,通过default来设置方法的默认值。

     

    下面是代码:

     

    package com.array7.annotationTest;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Inherited;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Documented
    @Target(ElementType.METHOD)
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    public @interface MethodInfo {
    	String author() default "array7";	// 作者
    	String date();	// 日期
    	double version() default 1.0;	// 版本号
    	String comments();	// 注释
    }
    

    然后定义个调用注解的类:

    package com.array7.annotationTest;
    
    public class AnnotationExample {
    	/**
    	 * 非静态方法
    	 * @param msg
    	 */
    	@MethodInfo(author = "七郎", comments = "方法测试注释:print10", date = "2013-11-29", version = 1.0)
    	public void print10(Object msg) {
    		System.out.println(msg);
    	}
    	
    	/**
    	 * 静态方法
    	 */
    	@MethodInfo(author = "七郎", comments = "方法测试注释:print20", date = "2013-11-20", version = 2.0)
    	public static void print20() {
    		System.out.println("test");
    	}
    }
    


    最后就是注解解析类(简单起见我将代码写在了main方法里):


    package com.array7.annotationTest;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class AnnotationParsing {
    	public static void main(String[] args) {
    		try {
    			Class<?> clazz = Class.forName("com.array7.annotationTest.AnnotationExample");	// 这里可以封装成动态代理类。
    			// Class clazz = AnnotationParsing.class.getClassLoader().loadClass("com.array7.annotationTest.AnnotationExample");	// 这种方式也OK。
    			for (Method method : clazz.getMethods()) {
    				if (method.isAnnotationPresent(MethodInfo.class)) {
    					for (Annotation anno : method.getAnnotations()) {
    						System.out.println("Annotation in Method [" + method + "]:" + anno);
    						MethodInfo methodInfo = method.getAnnotation(MethodInfo.class);
    						if (methodInfo.version() == 1.0) {
    							method.invoke(clazz.newInstance(), methodInfo.comments());
    						} else if (methodInfo.version() == 2.0) {
    							method.invoke(null);
    						}
    					}
    				}
    			}
    		} catch (SecurityException e) {
    			e.printStackTrace();
    		} catch (ClassNotFoundException e) {
    			e.printStackTrace();
    		} catch (IllegalAccessException e) {
    			e.printStackTrace();
    		} catch (IllegalArgumentException e) {
    			e.printStackTrace();
    		} catch (InvocationTargetException e) {
    			e.printStackTrace();
    		} catch (InstantiationException e) {
    			// TODO Auto-generated catch block
    			e.printStackTrace();
    		}
    		
    	}
    }
    


    程序最后输出:

     

    Annotation in Method [public void com.array7.annotationTest.AnnotationExample.print10(java.lang.Object)]:@com.array7.annotationTest.MethodInfo(author=七郎, version=1.0, comments=方法测试注释, date=2013-11-20)
    方法测试注释
    Annotation in Method [public static void com.array7.annotationTest.AnnotationExample.print20()]:@com.array7.annotationTest.MethodInfo(author=七郎, version=2.0, comments=方法测试注释, date=2013-11-20)
    test
    

    通过上述输出我们也可以发现,注解有限执行的是实例化之后的方法,然后才是静态方法。

     

    上面所提到的知识理论和实践,是本人通过书籍、Java文档、互联网资料总结并亲自验证的。

    如果哪位道友发现有表达不准确的地方,欢迎指正,免得误人误己,多谢。

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    二维数组输出10行杨辉三角
    二维数组的练习----求和
    数组的异常及处理
    二维数组在内存中的结构
    Ubuntu系统中安装Mercurial 以支持hg
    什么是插补、直线插补、联动与插补
    压力表(负压表...)
    常用接近开关的原理和分类
    VMware Ubuntu安装详细过程
    Redis+Spring缓存实例(windows环境,附实例源码及详解)
  • 原文地址:https://www.cnblogs.com/liushijie/p/4712935.html
Copyright © 2020-2023  润新知