全面解析Java注解

1.  了解注解

我们有必要对JDK 5.0新增的注解(Annotation)技术进行简单的学习,因为Spring 支持@AspectJ,而@AspectJ本身就是基于JDK 5.0的注解技术。所以学习JDK 5.0的注解知识有助于我们更好地理解和掌握Spring的AOP技术。

对于Java开发人员来说,在编写代码时,除了源程序以外,我们还会使用 Javadoc标签对类、方法或成员变量进行注释,以便使用Javadoc工具生成和源代码配套的Javadoc文档。这些@param、@return 等Javadoc标签就是注解标签,它们为第三方工具提供了描述程序代码的注释信息。使用过Xdoclet的朋友,对此将更有感触,像Struts、 Hibernate都提供了Xdoclet标签,使用它们可以快速地生成对应程序代码的配置文件。

JDK5.0注解可以看成是Javadoc标签和Xdoclet标签的延伸和发展。在JDK5.0中,我们可以自定义这些标签,并通过Java语言的反射机制中获取类中标注的注解,完成特定的功能。

注解是代码的附属信息,它遵循一个基本原则:注解不能直接干扰程序代码的运行,无论增加或删除注解,代码都能够正常运行。Java语言解释器会忽略这些注解,而由第三方工具负责对注解进行处理。第三方工具可以利用代码中的注解间接控制程序代码的运行,它们通过Java反射机制读取注解的信息,并根据这些信息更改目标程序的逻辑,而这正是Spring AOP对@AspectJ提供支持所采取的方法。

注解的语法比较简单,除了@符号的使用以外,它基本上与java的固有语法一致,java内置了三种注解,定义在java.lang包中。

@Override:只能用在方法之上的,用来告诉别人这一个方法是改写父类的。

@Deprecated:建议别人不要使用旧的API的时候用的,编译的时候会用产生警告信息,可以设定在程序里的所有的元素上。

@SuppressWarnings:表示关闭一些不当的编译器警告信息。

2.  定义注解

下面是一个定义注解的实例。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Description {
 
 String value();
}

其中的@interface是一个关键字,在设计annotations的时候必须把一个类型定义为@interface,而不能用class或interface关键字。所有的注解类都隐式继承于 java.lang.annotation.Annotation,注解不允许显式继承于其他的接口。

一个注解可以拥有多个成员,成员声明和接口方法声明类似,这里,我们仅定义了一个成员,成员的声明有以下几点限制:

a)   成员以无入参无抛出异常的方式声明,如boolean value(String str)、boolean value() throws Exception等方式是非法的;

b)   可以通过default为成员指定一个默认值,如String level() default "LOW_LEVEL"、int high() default 2是合法的,当然也可以不指定默认值;

c)   成员类型是受限的,合法的类型包括原始类型及其封装类、String、Class、enums、注解类型,以及上述类型的数组类型。如ForumService value()、List foo()是非法的。

d)   如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=),如@Description("使用注解的实例")。注解类拥有多个成员时,如果仅对value成员进行赋值则也可不使用赋值号,如果同时对多个成员进行赋值,则必须使用赋值号,如@DeclareParents (value = "NaiveWaiter", defaultImpl = SmartSeller.class)。

e)   注解类可以没有成员,没有成员的注解称为标识注解,解释程序以标识注解存在与否进行相应的处理;

注解定义包含四个元注解,分别为@Target,@Retention,@Documented,@Inherited。各元注解的作用如下:

1)  @Target

表示该注解用于什么地方,可能的 ElemenetType 参数包括:

Ø  ElemenetType.CONSTRUCTOR 构造器声明。

Ø  ElemenetType.FIELD 域声明(包括 enum 实例)。

Ø  ElemenetType.LOCAL_VARIABLE 局部变量声明。

Ø  ElemenetType.METHOD 方法声明。

Ø  ElemenetType.PACKAGE 包声明。

Ø  ElemenetType.PARAMETER 参数声明。

Ø  ElemenetType.TYPE 类,接口(包括注解类型)或enum声明。

2)  @Retention

表示在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括:

Ø  RetentionPolicy.SOURCE 注解将被编译器丢弃。

Ø  RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃。

Ø  RetentionPolicy.RUNTIME VM将在运行期也保留注释,因此可以通过反射机制读取注解的信息。

举一个例子,如@Override里面的Retention设为SOURCE,编译成功了就不要这一些检查的信息,相反,@Deprecated里面的Retention设为RUNTIME,表示除了在编译时会警告我们使用了哪个被 Deprecated的方法,在执行的时候也可以查出该方法是否被Deprecated。

3)  @Documented

将此注解包含在 javadoc 中

4)  @Inherited

允许子类继承父类中的注解

3.  使用注解

下面是一个使用注解注解的实例。

@Description(value="使用注解的实例")
public class TestAnnotation {

}

使用注解的语法:@<注解名>(<成员名1>=<成员值1>,<成员名1>=<成员值1>,...)

如果成员是数组类型,可以通过{}进行赋值,如boolean数组的成员可以设置为{true,false,true}。下面是几个注解标注的例子:

1)   多成员的注解

@AnnoExample(id= 2868724, synopsis = "Enable time-travel", engineer = "Mr. Peabody")

2)   一个成员的注解,成员名为value

可以省略成员名和赋值符号:@Copyright("Right Reserved")

@Copyright("2011 bookegou.com All Right Reserved")

3)   无成员的注解

@Override

@Override

4)   成员为字符串数组的注解

@SuppressWarnings(value={"unchecked","fallthrough"})

@SuppressWarnings(value={"unchecked","fallthrough"})

5)   成员为注解数组类型的注解

@Reviews({@Review(grade=Review.Grade.EXCELLENT,reviewer="df"),

@Review(grade=Review.Grade.UNSATISFACTORY,reviewer="eg",

comment="This method needs an @Override annotation")})

@Reviews({@Review(grade=Review.Grade.EXCELLENT,reviewer="df"),

@Review(grade=Review.Grade.UNSATISFACTORY,reviewer="eg",

comment="This method needs an @Override annotation")})

@Reviews注解拥有一个@Review注解数组类型的成员,@Review注解类型有三个成员,其中reviewer、comment都是String类型,但comment有默认值,grade是枚举类型的成员。

4.  解析注解

下面是一个解析注解的实例。

public class ParseAnnotation {
 
 public static void main(String[] args) throws Exception{
  final Class cls = Class.forName("com.annotation.TestAnnotation");
  final Method[] method = cls.getMethods();
  
  // 判断是否有指定注解类型的注解
  if(cls.isAnnotationPresent(Description.class)) {
   // 根据注解类型返回指定类型的注解
   Description des = (Description)cls.getAnnotation(Description.class);
   System.out.println("注解描述:" + des.value());
  }
 }
}

输出结果如下:

注解描述:使用注解的实例

前面提到过,注解不会直接影响程序的运行,但是第三方程序或工具可以利用代码中的注解完成特殊的任务,间接控制程序的运行。对于RetentionPolicy.RUNTIME保留期限的注解,我们可以通过反射机制访问类中的注解。

在JDK5.0里,Package、Class、Constructor、 Method以及Field等反射对象都新增了访问注解信息的方法:<T extends Annotation>T getAnnotation(Class<T> annotationClass),该方法支持通过泛型直接返回注解对象。

时间: 2024-10-08 03:17:03

全面解析Java注解的相关文章

【iMooc】全面解析java注解

在慕课上学习了一个关于java注解的课程,下面是笔记以及一些源码. Annotation--注解 1.JDK中的注解 JDK中包括下面三种注解: @Override:标记注解(marker annotation),重写,父类写的方法,如果子类继承了父类,就要重写父类的方法. @Deprecated:表示过时的语法加上这个注解之后,该方法上会出现一道删除线 @SuppressWarning:忽略警告,压制警告.如果某语句前面出现警告,加上这个注解,警告就会消失. 举例如下: 父类 一个Person

Java注解入门

注解的分类 按运行机制分: 源码注解:只在源码中存在,编译后不存在 编译时注解:源码和编译后的class文件都存在(如@Override,@Deprecated,@SuppressWarnings) 运行时注解:能在程序运行时起作用(如spring的依赖注入) 按来源分: 来自JDK的注解 第三方的注解 自定义的注解 自定义注解   如下实例给出了自定义注解的基本方法 1 package com.flypie.annotations; 2 3 import java.lang.annotatio

Java注解全面解析(转)

1.基本语法 注解定义看起来很像接口的定义.事实上,与其他任何接口一样,注解也将会编译成class文件. @Target(ElementType.Method) @Retention(RetentionPolicy.RUNTIME) public @interface Test {} 除了@符号以外,@Test的定义很像一个空的接口.定义注解时,需要一些元注解(meta-annotation),如@Target和@Retention @Target用来定义注解将应用于什么地方(如一个方法或者一个

[笔记]Java注解全面解析

JAVA注解 注解(Annotation),也叫元数据.一种代码级别的说明.它是JDK1.5及以后版本引入的一个特性,与类.接口.枚举是在同一个层次.它可以声明在包.类.字段.方法.局部变量.方法参数等的前面,用来对这些元素进行说明,注释. 1.注解分类 1.1按照运行机制分类 源码注解 注解只在源码中存在,编译成.class文件就不存在了 编译时注解 注解在源码和.class文件中都存在 比如: @Override @Deprecated @Suppvisewarnings 运行时注解 在运行

Java注解教程:自定义注解示例,利用反射进行解析

Java注解能够提供代码的相关信息,同时对于所注解的代码结构又没有直接影响.在这篇教程中,我们将学习Java注解,如何编写自定义注解,注解的使用,以及如何使用反射解析注解. 注解是Java 1.5引入的,目前已被广泛应用于各种Java框架,如Hibernate,Jersey,Spring.注解相当于是一种嵌入在程序中的元数据,可以使用注解解析工具或编译器对其进行解析,也可以指定注解在编译期或运行期有效. 在注解诞生之前,程序的元数据存在的形式仅限于java注释或javadoc,但注解可以提供更多

java注解(Annotation)解析

注解(Annotation)在java中应用非常广泛.它既能帮助我们在编码中减少错误,(比如最常见的Override注解),还可以帮助我们减少各种xml文件的配置,比如定义AOP切面用@AspectJ模式代替Schema模式,特别是最近接触了一点Spring MVC,每次编写Controller的时候用@RequestMapping(),@RequestParam,@ResponseBody等等. 我们所用的java中自带的注解都是定义好了的,直接拿来用,它就能发挥作用.当然了,自己也可以定义注

Java注解(3)-注解处理器(编译期|RetentionPolicy.SOURCE)

注解的处理除了可以在运行时通过反射机制处理外,还可以在编译期进行处理.在编译期处理注解时,会处理到不再产生新的源文件为止,之后再对所有源文件进行编译. Java5中提供了apt工具来进行编译期的注解处理.apt是命令行工具,与之配套的是一套描述"程序在编译时刻的静态结构"的API:Mirror API(com.sun.mirror.*).通过Mirror API可以获取到被注解的Java类型元素的信息,从而提供自定义的处理逻辑.具体的处理工具交给apt来处理.编写注解处理器的核心是两个

java注解例子

java注解在web框架中使用比较广泛,这使得对象之间的关系配置起来更加容易 目前web框架中最常用的两种配置对象依赖关系的方式就是注解和xml配置文件的方法,api配置相对来说用的少一些, 下面实现一个Table注解来实现数据库表和实体bean之间的对应关系,实现一个Column注解来实现数据库表中每个字段和实体bean每个属性之间的 对应关系.java中的orm基本上就是根据这种思想来实现的. Table注解代码: package com.panther.dong.annotation.an

Java注解(一):初识Java注解

参考:http://www.cnblogs.com/skywang12345/p/3344137.html http://www.cnblogs.com/taoxiaoji/archive/2011/01/19/1939651.html    http://blog.csdn.net/tigerdsh/article/details/8848890 http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html 首先知道注解是什么,能干什