• 再说注解


        当今的各种框架:Hibernate、Struts、Spring等,包含EJB,都支持注解形式,注解相比XML配置而言确实更为简洁,先来说说关于注解"what is"的问题。

    注解

        从形式上看,注解是类似凝视,它为代码提供了一种新的标识方式,能够在编译器先定义、使用,等到执行时再去解析这些注解相应的含义。在JDK1.5中引入,如今的JDK已经把注解的地位提升到和二进制码同样,当然假设你略微关注过注解,你应该知道注解解析过程的基础是反射原理。

        它为什么能够使用反射原理?对照类载入使用反射可知,虚拟机在载入class文件时,也会为注解分配空间并解析,终于还会为注解和相应的二进制码建立关联,这就为使用反射提供了基础。

        注解不过用于标注,并不会主动执行,也不会影响主代码的逻辑,只起到辅助性的作用,但其对代码的说明能力,结合反射技术已经给了我们非常大的想象空间。


        从宏观上看,注解的运行共分为3部分:
    • 定义注解
    • 使用注解
    • 解析注解

        定义注解

        说到定义注解须要先说一下元注解,即定义注解的注解,共同拥有四种:@Retention @Target @Document @Inherited:

    • @Retention:注解的生命时长:编译期、执行期……
    • @Target:应用位置:字段、方法、类……
    • @Documented:是否被包括在javadoc中
    • @Inherited:子类能否够继承父类该注解

        有关这几个元注解的说明不再细说,有兴趣能够查看元注解的源代码,位于java.lang.annotation下,另有部分注解位于javax.annotation下。

        使用注解

        使用注解的方式非经常见也非常简答,如@MyAnnotation(ElementType.RealNew),将此注解加到类、字段、方法等上即表明此注解关联到该类的指定项上。

        解析注解

        这三步中,事实上这是最后也是最关键的一步,上面定义、使用再好,没有一个专门解析注解的类,前面都是白写,解析注解实例会在以下说明,解析的核心步骤是:

    • 得到使用注解的类
    • 使用反射得到类中的字段、方法等
    • 得到使用了指定注解的方法、字段等,及其注解的值
    • 编写一个函数,依据注解类型及注解值进行指定操作

    实例

        依据以上所说,编写了一个注解实例,实例内容为:当检測到House属性中有我们自己定义的注解时,向House注入一个Dog。

        文件说明

    • NewMePolicy:定义一个枚举,指定注解能够使用的參数
    • NewMeAnnotation:定义一个注解
    • Dog:辅助使用注解的类
    • House:使用我们自己定义注解的类
    • TestAnnotation:解析注解的类

        NewMePolicy

    package annotation;
    
    public enum NewMePolicy {
    
    	//使用单例模式获取对象
    	Singleton,
    	//创建新对象
    	RealNew,
    	//忽视此注解
    	Ignore
    }
    

        NewMeAnnotation

    package annotation;
    
    import java.lang.annotation.Documented;
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface NewMeAnnotation {
    	NewMePolicy category();
    	public String className();
    }

        House

    package annotation;
    
    public class House {
    
    	@NewMeAnnotation(category=NewMePolicy.RealNew,className="annotation.Dog")
    	private Class<?> cat;
    	
    	private String other;
            
            // 省略getter和setter方法
    
    }

        TestAnnotation

    package annotation;
    
    import java.lang.annotation.Annotation;
    import java.lang.reflect.Field;
    import java.util.HashMap;
    
    public class TestAnnotation {
    
    	public static void main(String [] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException
    	{
    		//定义一个暂时的HashMap,用于保存全部涉及到的用户自己定义类实例
    		HashMap<String, Object> temp=new HashMap<String, Object>();
    		//定义另外一个HashMap,用于保存处理过的用户自己定义类实例
    		HashMap<String, Object> objMap=new HashMap<String, Object>();
    		//载入House类
    		Class<?> uaClass=Class.forName("annotation.House");
    		//利用反射得到其全部的属性
    		Field[] fields=uaClass.getDeclaredFields();
    		//遍历得到的属性
    		for (Field field:fields) {
    			//该字段是否使用了我们自己定义的注解
    			boolean hasAnnotation=field.isAnnotationPresent((Class<? extends Annotation>) NewMeAnnotation.class);
    			if (hasAnnotation) {
    				//得到有NewMeAnnotation注解的字段
    				NewMeAnnotation annotations=field.getAnnotation(NewMeAnnotation.class);
    				//打印查看注解实例化的策略
    				System.out.println("注入的策略为: "+annotations.category());
    				//打印要注入的内容
    				System.out.println("注入的类为: "+annotations.className());
    				if (NewMePolicy.RealNew.equals(annotations.category())) {
    					//找到相应的类,实例化
    					Class<?> cat=Class.forName(annotations.className().toString());
    					House house= (House) uaClass.newInstance();
    					//将两个类的实例保存到temp中
    					temp.put(uaClass.toString(), house);
    					temp.put(Dog.class.toString(), cat);
    					//注入实例
    					house.setCat(cat);
    					//保存定义好的UseAnnotation实例
    					objMap.put(uaClass.toString(), house);
    				}
    				
    				System.out.println("类: "+uaClass+"已经完毕初始化");
    			}
    			else {
    				System.out.println("字段:"+field+" 没有NewMeAnnotation注解!");
    			}
    		}
    	}
    }
    

        控制台输出

    注入的策略为: RealNew
    注入的类为: annotation.Dog
    类: class annotation.House已经完毕初始化
    字段:private java.lang.String annotation.House.other 没有NewMeAnnotation注解!

        能够看到,我们能够使用反射获取到字段,及字段的注解,依据注解内容,我们能够动态的将注解规定的类Dog注入到House中,当然这个样例在解析的时候还不是非常全,比方没有解析假设注解的category为singleton、Ignore时怎样处理,可是作为一个解释注解的样例,我觉得足够了。

    总结

        这个注解的样例是使用setter将一个bean注入到另外一个bean中,有没有认为有些眼熟,对Spring,稍后的文章会解释Spring是怎样依据注解管理bean之间的关系。


  • 相关阅读:
    事事浑不着意,总得有走心的地方
    Struts2框架概述
    java算法数据结构
    shell十三问(转)
    linux:将job放在后台执行的方法
    Python性能(转)
    python collections deque
    python中的参数传递和返回值
    python中的下划线
    python学习笔记glob模块
  • 原文地址:https://www.cnblogs.com/yxwkf/p/4554454.html
Copyright © 2020-2023  润新知