黑马程序员_java注解

注解(Annotation)简介 
Annotation(注解)是JDK5.0及以后版本引入的一个特性。注解是java的一个新的类型(与接口很相似),它与类、接口、枚举 是在同一个层次,它们都称作为java的一个类型(TYPE)。它可以声明在包、类、字段、方法、局部变量、方法参数等 的前面,用来对这些元素进行说明,注释。它的作用非常的多,例如:进行编译检查、生成说明文档、代码分析等。
 
注解的作用
注解可以看成是一个接口,注解实例就是一个实现了该接口的动态代理类。 注解大多是用做对某个类、方法、字段进行说 明,标识的。以便在程序运行期间我们通过反射获得该字段或方法的注解的实例,来决定该做些什么处理或不该进行什 么处理。
 
JDK提供的几个基本注解 
a. @SuppressWarnings 
该注解的作用是阻止编译器发出某些警告信息。
它可以有以下参数: 
deprecation:过时的类或方法警告。 
unchecked:执行了未检查的转换时警告。 
fallthrough:当Switch程序块直接通往下一种情况而没有Break时的警告。
path:在类路径、源文件路径等中有不存在的路径时的警告。
serial:当在可序列化的类上缺少serialVersionUID定义时的警告。
finally:任何finally子句不能完成时的警告。
all:关于以上所有情况的警告。
b.@Deprecated 该注解的作用是标记某个过时的类或方法。
c. @Override 该注解用在方法前面,用来标识该方法是重写父类的某个方法。
 
元注解 
元注解是指注解的注解。包括  @Retention @Target @Document @Inherited四种。
a. @Retention 它是被定义在一个注解类的前面,用来说明该注解的生命周期。
@Retention 表示在什么级别保存该注解信息。可选的参数值在枚举类型 RetentionPolicy 中,
 
它有以下参数:            
 @Retention(RetentionPolicy.SOURCE)//注解仅存在于源码中,在class字节码文件中不包含     
 @Retention(RetentionPolicy.CLASS)// 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得, 
 @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到  
 @Documented 将此注解包含在 javadoc 中 ,它代表着此注解会被javadoc工具提取成文档。在doc文档中的内容 会因为此注解的信息内容不同而不同。相当与@see,@param 等。       
 @Inherited 允许子类继承父类中的注解
 
思考:@Override、@SuppressWarnings和@Deprecated这三个注解的属性值分别是什么?
@Override、@SuppressWarnings的属性值是SOURCE。
@Deprecated的属性值是RUNTIME。
 
b. @Target 它是被定义在一个注解类的前面,用来说明该注解可以被声明在哪些元素,可能的值在枚举类 
 
ElemenetType中。
它有以下参数: 
@Target(ElementType.TYPE)   //接口、类、枚举、注解   
@Target(ElementType.FIELD) //字段、枚举的常量   
@Target(ElementType.METHOD) //方法    
@Target(ElementType.PARAMETER) //方法参数    
@Target(ElementType.CONSTRUCTOR)  //构造函数  
@Target(ElementType.LOCAL_VARIABLE)//局部变量   
@Target(ElementType.ANNOTATION_TYPE)//注解         
@Target(ElementType.PACKAGE) //包 packag注解必须在package-info.java 中声明 
 
注解的生命周期
一个注解可以有三个生命周期,它默认的生命周期是保留在一个CLASS文件,但它也可以由一个@Retetion的元注解指定它 的生命周期。
a.java源文件 当在一个注解类前定义了一个@Retetion(RetentionPolicy.SOURCE)的注解,那么说明该注解只保留在一个源文 件当中,当编译器将源文件编译成class文件时,它不会将源文件中定义的注解保留在class文件中。
b. class文件中 当在一个注解类前定义了一个@Retetion(RetentionPolicy.CLASS)的注解,那么说明该注解只保留在一个 class文件当中,当加载class文件到内存时,虚拟机会将注解去掉,从而在程序中不能访问。
c. 程序运行期间 当在一个注解类前定义了一个@Retetion(RetentionPolicy.RUNTIME)的注解,那么说明该注解在程序运行期 间都会存在内存当中。此时,我们可以通过反射来获得定义在某个类上的所有注解。
 
注解的定义 
一个简单的注解: 
public@interfaceAnnotation01{ 
//定义公共的final静态属性
..... 
//定以公共的抽象方法
......} 
a.注解可以有哪些成员 注解和接口相似,它只能定义final静态属性和公共抽象方法。
b.注解的方法 
1.方法前默认会加上publicabstract
2.在声明方法时可以定义方法的默认返回值。 
例如: Stringcolor()default"blue"; 
      String[]color()default{"blue","red",......}
3.方法的返回值可以有哪些类型 8种基本类型,String、Class、枚举、注解及这些类型
 
的数组。 
c.使用注解(参照下面的注解使用)
 
注解的使用 
注解的使用分为三个过程。 
定义注解-->声明注解-->得到注解 
a.定义注解(参照上面的注解定义)
b.声明注解 
1.在哪些元素上声明注解 
如果定义注解时没有指定@Target元注解来限制它的使用范围,那么该注解可以
 
使用在ElementType枚举指定的任何一个元素前。否则,只能声明在@Target元
 
注解指定的元素前。 
一般形式:
@注解名() 
2.对注解的方法的返回值进行赋值 对于注解中定义的每一个没有默认返回值的方法,在
 
声明注解时必须对它的每一个方法的返回值进行赋值。 
一般形式: 
@注解名(方法名=方法返回值,...) 
如果方法返回的是一个数组时,那么将方法返回值写在{}符号里 
@注解名(方法名={返回值1,返回值2,...}...) 
3.对于只含有value方法的注解,在声明注解时可以只写返回值。
c.得到注解 对于生命周期为运行期间的注解,都可以通过反射获得该元素上的注解实例。 
1、声明在一个类中的注解 
可以通过该类Class对象的getAnnotation或getAnnotations方法获得。
2、声明在一个字段中的注解 
通过Field对象的getAnnotation或getAnnotations方法获得
3、声明在一个方法中的注解 
通过Method对象的getAnnotation或getAnnotations方法获得
为注解增加高级属性
数组类型的属性
int [] arrayAttr() default {1,2,3};
@MyAnnotation(arrayAttr={2,3,4})
如果数组属性中只有一个元素,这时候属性值部分可以省略大括
枚举类型的属性
EnumTest.TrafficLamp lamp() ;
@MyAnnotation(lamp=EnumTest.TrafficLamp.GREEN)
注解类型的属性:
MetaAnnotation annotationAttr() default @MetaAnnotation("xxxx");
@MyAnnotation(annotationAttr=@MetaAnnotation(“yyy”) )
可以认为上面这个@MyAnnotation是MyAnnotaion类的一个实例对象,同样的道理,可以认为上面这个 @MetaAnnotation是MetaAnnotation类的一个实例对象,调用代码如下:
MetaAnnotation ma =  myAnnotation.annotationAttr();
System.out.println(ma.value());
注解的详细语法可以通过看java语言规范了解,即看java的language specification。
 
实例:
下面是使用反射读取RUNTIME保留策略的Annotation信息的例子:
 
自定义注解:
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String[] value1() default "abc";
}
 
 
使用自定义注解:
public class AnnotationTest2 {  
  @MyAnnotation(value1={"a","b"})
    @Deprecated
    public void execute(){
        System.out.println("method");
    }
}
 
 
读取注解中的信息:
public static void main(String[] args) throws SecurityException, NoSuchMethodException, 
 
IllegalArgumentException, IllegalAccessException, InvocationTargetException {
    AnnotationTest2 annotationTest2 = new AnnotationTest2();
    //获取AnnotationTest2的Class实例
    Class<AnnotationTest2> c = AnnotationTest2.class;
    //获取需要处理的方法Method实例
    Method method = c.getMethod("execute", new Class[]{});
    //判断该方法是否包含MyAnnotation注解
    if(method.isAnnotationPresent(MyAnnotation.class)){
        //获取该方法的MyAnnotation注解实例
        MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
        //执行该方法
        method.invoke(annotationTest2, new Object[]{});
        //获取myAnnotation
        String[] value1 = myAnnotation.value1();
        System.out.println(value1[0]);
    }
    //获取方法上的所有注解
    Annotation[] annotations = method.getAnnotations();
    for(Annotation annotation : annotations){
        System.out.println(annotation);
    }
}
 
 
总结
1. 要用好注解,必须熟悉java 的反射机制,从上面的例子可以看出,注解的解析完全依赖于反射。
2. 不要滥用注解。平常我们编程过程很少接触和使用注解,只有做设计,且不想让设计有过多的配置时。

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。