xscn

博客园 首页 新随笔 联系 订阅 管理

 

概念

AnnontationJava5开始引入的新特征。中文名称一般叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据与程序元素(类、方法、成员变量等)进行关联。更通俗的意思是为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且是供指定的工具或框架使用的。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。

Annotation为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻方便地使用这些数据(通过解析注解来使用这些数据)常见的作用有以下几种:

  • 生成文档。这是最常见的,也是java 最早提供的注解。常用的有@see @param @return 等
  • 跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5 开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。也是
  • 在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

原理

  Annotation其实是一种接口。通过Java的反射机制相关的API来访问annotation信息。相关类(框架或工具中的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。

java提供的几个基本注解

在jdk1.5的java.lang包中预定义了三个注解。分别是Override、Deprecated和SuppressWarnings。

Override

表示一个方法声明打算重写超类中的另一个方法声明。如果方法利用此注释类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。这个注解的作用是标识某一个方法是否覆盖了它的父类的方法,常常在我们试图覆盖父类方法却又写错了方法名时提供了一个保障性的校验过程。

Deprecated

用 @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器会发出警告。

SuppressWarnings

指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。注意,在给定元素中取消显示的警告集是所有包含元素中取消显示的警告的超集。例如,如果注释一个类来取消显示某个警告,同时注释一个方法来取消显示另一个警告,那么将在此方法中同时取消显示这两个警告。根据风格不同,程序员应该始终在最里层的嵌套元素上使用此注释,在那里使用才有效。如果要在特定的方法中取消显示某个警告,则应该注释该方法而不是注释它的类。

此注解能告诉Java编译器关闭对类、方法及成员变量的警告。有时编译时会提出一些警告,对于这些警告有的隐藏着Bug,有的是无法避免的,对于某些不想看到的警告信息,可以通过这个注解来屏蔽。

例如

1 import java.util.*;
2 public class AnnotationTest {    
3      
4          public static void main(String[] args) {    
5         
6          List li =new ArrayList();
7          li.add("abc");
8     }  
9 }

这个类编译的时候会出现如下警告:

注: AnnotationTest.java使用了未经检查或不安全的操作。
注: 有关详细信息, 请使用 -Xlint:unchecked 重新编译。

要解决这个问题:

1.可以为List集合加上泛型限定元素类型

2.可以在第三行代码处加上@SuppressWarnings (value={"unchecked"})

java中的元注解

Rentention

注解的生命周期:Java源文件—》class文件—》内存中的字节码。编译或者运行时,都有可能会取消注解。
默认值是枚举RententionPolicy的3种取值意味让注解保留到哪个阶段:

RententionPolicy.SOURCE的作用是不将注解保存在class文件中,也就是说象“//”一样在编译时被过滤掉了。

RententionPolicy.CLASS(默认值)的作用是只将注解保存在class文件中,而使用反射读取注解时忽略这些注解。   

RententionPolicy.RUNTIME的作用是即将注解保存在class文件中,可以通过反射读取注解。    

@Override、@SuppressWarnings是默认保留到SOURCE阶段;@Deprecated是保留到RUNTIME阶段。

总的说,Rentention相当于注解类的一个属性,因为Rentention的值不同,注解类保留到的阶段不同。  

Target 

指示注释类型所适用的程序元素的种类。如果注释类型声明中不存在 Target 元注释,则声明的类型可以用在任一程序元素上。如果存在这样的元注释,则编译器强制实施指定的使用限制。通俗的讲,就是注释应用在哪个目标上。

取值为枚举ElementType中的值

ANNOTATION_TYPE
注释类型声明
CONSTRUCTOR
构造方法声明
FIELD
字段声明(包括枚举常量)
LOCAL_VARIABLE
局部变量声明
METHOD
方法声明
PACKAGE
包声明
PARAMETER
参数声明
TYPE
类、接口(包括注释类型)或枚举声明

Documented

指示某一类型的注释将通过 javadoc 和类似的默认工具进行文档化。应使用此类型来注释这些类型的声明:其注释会影响由其客户端注释的元素的使用。如果类型声明是用 Documented 来注释的,则其注释将成为注释元素的公共 API 的一部分。在默认的情况下在使用javadoc自动生成文档时,注解将被忽略掉。如果想在文档中也包含注解,必须使用Documented为文档注解。

Inherited

在默认的情况下,父类的注解并不会被子类继承。如果要继承,就必须加上Inherited注解。

 

为注解增加高级属性

数组类型的属性
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”) )

自定义注解

需求:

(1)定义两个自定义注解类,要求可以使用简写方式为属性赋值。

1.定义作者信息,name,group和value,注解的属性类型为String,int,并且可以被保留到程序运行时,使其注解在方法上;

2.定义版本信息edition,注解的属性类型为double,并且可以被保留到程序运行时,使其注解在类上。

(2)定义一个类MyClass,要求有三个方法method1、2、3

使用(1)中的注解1来注释method1,2,3,并对属性参数分别赋值。其中method3使用缺省赋值。

(3)定义一个测试类,要求使用反射来测试MyClass中所有的被注解的方法。

 1 import java.lang.annotation.*;
 2  /**
 3  定义作者信息,name,group,value
 4  */
 5     @Retention(RetentionPolicy.RUNTIME)
 6     @Target(ElementType.METHOD)
 7 public @interface Author {
 8         String name()default "XXX";
 9         int value()default 8888;
10         String group()default "other";
11 }

 

1 import java.lang.annotation.*;
2  /**
3 定义版本信息 edition
4 */
5     @Retention(RetentionPolicy.RUNTIME)
6     @Target(ElementType.TYPE)
7 public @interface Edition {
8        double value();
9 }

 

 

 1 @Edition(1.0)
 2 public class MyClass {
 3 
 4         @Author(name = "zhangsan",group="com.itheima",value=123)
 5         public void method1(){}
 6 
 7         @Author(name = "wangwu",group="com.itheima",value=456)
 8         public void method2(){}
 9     
10         @Author
11         public void method3(){}
12 
13 }

 

 1 import java.lang.reflect.Method;
 2 public class AnnotationTest {
 3 /**
 4 在运行时通过反射分析处理annotation类型的信息 
 5 */
 6     public static void main(String[] args) {
 7         try {
 8                 System.out.println("版本信息:");
 9                 if(MyClass.class.isAnnotationPresent(Edition.class))
10                 {   //用反射方式获得注解对应的实例对象
11                     Edition edition = (Edition)MyClass.class.getAnnotation(Edition.class);
12                     //通过该对象调用属性对应的方法
13                     System.out.println(edition.value());
14                 }
15                 System.out.println("作者信息:");
16                 Method[] methods = MyClass.class.getMethods();
17                 for (Method method : methods) {
18                      if(method.isAnnotationPresent(Author.class))
19                       {
20                         Author author = (Author)method.getAnnotation(Author.class);
21                         System.out.println(author.name()+"\t"+author.group()+"\tID"+author.value());                      
22                       }
23                     }   
24             } catch (Exception e) {
25                 e.printStackTrace();
26             }
27     }
28 }
29 ---------- 运行 ----------
30 版本信息:
31 1.0
32 作者信息:
33 zhangsan    com.itheima    ID123
34 wangwu    com.itheima    ID456
35 XXX    other    ID8888
36 
37 输出完成 (耗时 0 秒) - 正常终止

 

posted on 2013-08-25 18:05  xscn  阅读(241)  评论(0编辑  收藏  举报