读书人

java annotation 引见

发布时间: 2012-10-26 10:30:58 作者: rapoo

java annotation 介绍
元数据的作用

如果要对于元数据的作用进行分类,目前还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类:

l 编写文档:通过代码里标识的元数据生成文档。

l 代码分析:通过代码里标识的元数据对代码进行分析。

l 编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查。



基本内置注释

@Override 注释能实现编译时检查,你可以为你的方法添加该注释,以声明该方法是用于覆盖父类中的方法。如果该方法不是覆盖父类的方法,将会在编译时报错。例如我们为某类重写toString() 方法却写成了tostring() ,并且我们为该方法添加了@Override 注释;

@Deprecated 的作用是对不应该在使用的方法添加注释,当编程人员使用这些方法时,将会在编译时显示提示信息,它与javadoc 里的 @deprecated 标记有相同的功能,准确的说,它还不如javadoc @deprecated ,因为它不支持参数,

注意:要了解详细信息,请使用 -Xlint:deprecation 重新编译。

@SuppressWarnings 与前两个注释有所不同,你需要添加一个参数才能正确使用,这些参数值都是已经定义好了的,我们选择性的使用就好了,参数如下:



deprecation 使用了过时的类或方法时的警告

unchecked 执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型

fallthrough 当 Switch 程序块直接通往下一种情况而没有 Break 时的警告

path 在类路径、源文件路径等中有不存在的路径时的警告

serial 当在可序列化的类上缺少 serialVersionUID 定义时的警告

finally 任何 finally 子句不能正常完成时的警告

all 关于以上所有情况的警告


定制注释类型

好的,让我们创建一个自己的注释类型(annotation type )吧。它类似于新创建一个接口类文件,但为了区分,我们需要将它声明为@interface, 如下例:

public @interface NewAnnotation {



}

使用定制的注释类型

我们已经成功地创建好一个注释类型NewAnnotation ,现在让我们来尝试使用它吧,如果你还记得本文的第一部分,那你应该知道他是一个标记注释,使用也很容易,如下例:


********************************************************************************



Annotation(注解)

Annotation对于程序运行没有影响,它的目的在于对编译器或分析工具说明程序的某些信息,您可以
在包,类,方法,域成员等加上Annotation.每一个Annotation对应于一个实际的Annotation类型.

1 限定Override父类方法@Override
java.lang.Override是J2SE5.0中标准的Annotation类型之一,它对编译器说明某个方法必须
是重写父类中的方法.编译器得知这项信息后,在编译程序时如果发现被@Override标示的方法
并非重写父类中的方法,就会报告错误.
例,如果在定义新类时想要重写Object类的toString()方法,可能会写成这样:
public class CustomClass{
public String ToString(){
return "customObject";
}
}
在编写toString()方法时,因为输入错误或其他的疏忽,将之写成ToString()了,编译这个类时
并不会出现任何的错误,编译器不会知道您是想重写toString()方法,只会以为是定义了一个新的ToString()方法.
可以使用java.lang.Override这个Annotation类型,在方法上加一个@Override的Annotation这可以告诉编译器现在定义的这个方法,必须是重写父类中的同包方法.
public class CustomClass{
@Override
public String toString(){
return "coustomObject";
}
}
java.lang.Override是一个Marker Annotation,简单地说就是用于标示的@Override是伪代码,表示重写(当然不写也可以),不过写上有如下好处:
1>可以当注释用,方便阅读

2>编译器可以给你验证@Override下面的方法名是否是你父类中所有的,如果没有则报错

比如你如果没写@Override而你下面的方法名又写错了,这时你的编译器是可以通过的(它以为这个方法是你的子类中自己增加的方法)

2 标示方法为Deprecated @Deprecated
java.lang.Deprecated也是J2SE5.0中标准的Annotation类型之一。它对编译器说明某个方法已经不
建议使用。如果有开发人员试图使用或重写被@Deprecated标示的方法,编译器必须提出警告信息。
例:
public class Something{
@Deprecated
public Something getSomething(){
return new Something();
}
}
如果有人试图在继承这个类后重写getSomething()方法,或是在程序中调用getSomething()方法,
则编译时会有警告出现。
java.lang.Deprecated也是一个Marker Annotation简单地说就是用于标示。

3 抑制编译器警告 @SuppressWarnings
java.lang.SuppressWarnings也是J2SE5.0中标准的Annotation类型之一,它对编译器说明某个方法
中若有警告信息,则加以抑制,不用在编译完成后出现警告。
例:
public class SomeClass2{
@SuppressWarnings(value={"unchecked"});
public void doSomething(){
Map map = new HashMap();
map.put("some","thing");
}
}
这样,编译器将忽略unchecked的警告,您也可以指定忽略多个警告:
@SuppressWarnings(value={"unchecked","deprecation"});
@SuppressWarnings是所谓的Single-Value Annotation,因为这样的Annotation只有一个成员,称为
value成员,可在使用Annotation时作额外的信息指定。

自定义Annotation类型
可以自定义Annotation类型,并使用这些自定义的Annotation类型在程序代码中使用Annotation,这些Annotation将提供信息给程序代码分析工具。

当使用@interface自行定义Annotation类型时,实际上是自动继承了
java.lang.annotation接口,并由编译器自动完成其他产生的细节,并且在定义Annotation类型时,
不能继承其他的Annotation类型或接口.


meta-annotation
所谓neta-annotation就是Annotation类型的数据,也就是Annotation类型的Annotation。在定义
Annotation类型时,为Annotation类型加上Annotation并不奇怪,这可以为处理Annotation类型
的分析工具提供更多的信息。

1 告知编译器如何处理annotation @Retention
java.lang.annotation.Retention类型可以在您定义Annotation类型时,指示编译器该如何对待自定
义的Annotation类型,编译器默认会将Annotation信息留在.class文件中,但不被虚拟机读取,而仅用
于编译器或工具程序运行时提供信息。

在使用Retention类型时,需要提供java.lang.annotation.RetentionPolicy的枚举类型。
RetentionPolicy的定义如下所示:
package java.lang.annotation;
public enum RetentionPolicy{
SOURCE,//编译器处理完Annotation信息后就没有事了
CLASS,//编译器将Annotation存储于class文件中,默认
RUNTIME //编译器将Annotation存储于class文件中,可由VM读入

}

RetentionPolicy为SOURCE的例子是@SuppressWarnings,这个信息的作用仅在编译时期告知
编译器来抑制警告,所以不必将这个信息存储在.class文件中。

RetentionPolicy为RUNTIME的时机,可以像是您使用Java设计一个程序代码分析工具,您必须让VM能读出
Annotation信息,以便在分析程序时使用,搭配反射机制,就可以达到这个目的。\

J2SE6.0的java.lang.reflect.AnnotatedElement接口中定义有4个方法:
public Annotation getAnnotation(Class annotationType)
public Annotation[] getAnnotations();
public Annotation[] getDeclaredAnnotations()
public boolean isAnnotationPresent(Class annotationType);

Class,Constructor,field,Method,Package等类,都实现了AnnotatedElement接口,所以可以从这些
类的实例上,分别取得标示于其上的Annotation与相关信息。由于在执行时读取Annotation信息,所以定
义Annotation时必须设置RetentionPolicy为RUNTIME,也就是可以在VM中读取Annotation信息。
例:
package onlyfun.caterpillar;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPllicy;

@Retention(RetentionPolicy.RUNTIME)
public @interface SomeAnnotation{
String value();
String name();
}
由于RetentionPolicy为RUNTIME,编译器在处理SomeAnnotation时,会将Annotation及给定的相关信息
编译至.class文件中,并设置为VM可以读出Annotation信息。接下来:
package onlyfun.caterpillar;
public class SomeClass3{
@SomeAnotation{
value="annotation value1",
name="annotation name1"
}
public void doSomething(){
......
}
}


现在假设要设计一个源代码分析工具来分析所设计的类,一些分析时所需的信息已经使用Annotation标示于类
中了,可以在执行时读取这些Annotation的相关信息。例:

  package onlyfun.caterpillar;    import java.lang.annotation.Retention;  import java.lang.annotation.RetentionPolicy;  import java.lang.annotation.Inherited;    @Retention(RetentionPolicy.RUNTIME)  @Inherited  public @interface ThreeAnnotation{    String value();    String name();  }  可以在下面的程序中使用@ThreeAnnotation:  public class SomeoneClass{    @onlyfun.caterpillar.ThreeAnnotation(      value = "unit",      name = "debug1"    )    public void doSomething(){      .....    }  }

如果有一个类继承了SomeoneClass类,则@ThreeAnnotation也会被继承下来。

可是,我们没事使用 Annotation 有什么用呢?和平时的注释又有什么区别?

原来,我们通过用Annotation的注解写了是给 比我们代码更高一级的代码看的,例如 Jpa用Annotation定义实体,这样框架就可以通过注解分析出实体的具体定义,然后Mapping到数据库。
或者,对项目控制也有一定的用途。当你完成了方法的需求的时候,加上 老大 给的注解,这样老大通过它的 RTTI 反射检查你写的代码。[b][/b][i][/i]

读书人网 >编程

热点推荐