`
jack_zhang
  • 浏览: 2114 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

JDK新增注解 (转)

阅读更多
有必要对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提供支持所采取的方法。

引用
很多东西的设计都必须遵循最基本的原则,为了防止机器人伤害人类,科幻作家阿西莫夫于1940年提出了“机器人三原则”:第一,机器人不能伤害人类;第二,机器人应遵守人类的命令,与第一条违背的命令除外;第三,机器人应能保护自己,与第一条违背的命令除外。这是给机器人赋予的伦理性纲领,机器人学术界一直将这三条原则作为机器人开发的准则。


一个简单的注解类

通常情况下,第三方工具不但负责处理特定的注解,本身还提供了这些注解的定义,所以我们通常仅需关注如何使用注解就可以了。但定义注解类本身并不困难,Java提供了定义注解的语法。下面,我们马上着手编写一个简单的注解类,如代码清单7-1所示:

代码清单7-1  NeedTest注解类
Java代码  收藏代码
package com.baobaotao.aspectj.anno; 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
 
@Retention(RetentionPolicy.RUNTIME) //①声明注解的保留期限 
@Target(ElementType.METHOD)//②声明可以使用该注解的目标类型 
public @interface NeedTest {//③定义注解 
    boolean value() default true;//④声明注解成员 



Java新语法规定使用@interface修饰符定义注解类,如③所示,一个注解可以拥有多个成员,成员声明和接口方法声明类似,这里,我们仅定义了一个成员,如④所示。成员的声明有以下几点限制:

成员以无入参无抛出异常的方式声明,如boolean value(String str)、boolean value() throws Exception等方式是非法的;
可以通过default为成员指定一个默认值,如String level() default "LOW_LEVEL"、int high() default 2是合法的,当然也可以不指定默认值;
成员类型是受限的,合法的类型包括原始类型及其封装类、String、Class、enums、注解类型,以及上述类型的数组类型。如ForumService value()、List foo()是非法的。


在①和②处,我们所看到的注解是Java预定义的注解,称为元注解(Meta-Annotation),它们被Java编译器使用,会对注解类的行为产生影响。@Retention(RetentionPolicy. RUNTIME)表示NeedTest这个注解可以在运行期被JVM读取,注解的保留期限类型在java.lang.annotation.Retention类中定义,介绍如下:

SOURCE:注解信息仅保留在目标类代码的源码文件中,但对应的字节码文件将不再保留;
CLASS:注解信息将进入目标类代码的字节码文件中,但类加载器加载字节码文件时不会将注解加载到JVM中,也即运行期不能获取注解信息;
RUNTIME:注解信息在目标类加载到JVM后依然保留,在运行期可以通过反射机制读取类中注解信息。   Target(ElementType.METHOD)表示NeedTest这个注解只能应用到目标类的方法上,注解的应用目标在java.lang.annotation.ElementType类中定义:
TYPE:类、接口、注解类、Enum声明处,相应的注解称为类型注解;
FIELD:类成员变量或常量声明处,相应的注解称为域值注解;
METHOD:方法声明处,相应的注解称为方法注解;
PARAMETER:参数声明处,相应的注解称为参数注解;
CONSTRUCTOR:构造函数声明处,相应的注解称为构造函数注解;
LOCAL_VARIABLE:局部变量声明处,相应的注解称为局域变量注解;
ANNOTATION_TYPE:注解类声明处,相应的注解称为注解类注解,ElementType. TYPE包括ElementType.ANNOTATION_TYPE;
PACKAGE:包声明处,相应的注解称为包注解。


如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=),如@NeedTest(true)。注解类拥有多个成员时,如果仅对value成员进行赋值则也可不使用赋值号,如果同时对多个成员进行赋值,则必须使用赋值号,如DeclareParents (value = "NaiveWaiter", defaultImpl = SmartSeller.class)。注解类可以没有成员,没有成员的注解称为标识注解,解释程序以标识注解存在与否进行相应的处理;此外,所有的注解类都隐式继承于java.lang.annotation.Annotation,但注解不允许显式继承于其他的接口。

我们希望使用NeedTest注解对业务类的方法进行标注,以便测试工具可以根据注解情况激活或关闭对业务类的测试。在编写好NeedTest注解类后,就可以在其他类中使用它了。

使用注解

我们在ForumService中使用NeedTest注解,标注业务方法是否需要测试,如代码清单7-2所示:

代码清单7-2  ForumService:使用注解
Java代码  收藏代码
package com.baobaotao.aspectj.anno; 
public class ForumService { 
    @NeedTest(value=true) ① 
    public void deleteForum(int forumId){ 
        System.out.println("删除论坛模块:"+forumId); 
    } 
    @NeedTest(value=false) ② 
    public void deleteTopic(int postId){ 
        System.out.println("删除论坛主题:"+postId); 
    }    



如果注解类和目标类不在同一个包中,需要通过import引用的注解类。在①和②处,我们使用NeedTest分别对deleteForum()和deleteTopic()方法进行标注。在标注注解时,可以通过以下格式对注解成员进行赋值:

引用
@<注解名>(<成员名1>=<成员值1>,<成员名1>=<成员值1>,...)


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

示例1,多成员的注解:
Java代码  收藏代码
@AnnoExample(id= 2868724, synopsis = "Enable time-travel", 
engineer = "Mr. Peabody",date = "4/1/2007") 


示例2,一个成员的注解,成员名为value。可以省略成员名和赋值符号:

Java代码  收藏代码
@Copyright("2011 bookegou.com All Right Reserved") 


示例3,无成员的注解:

Java代码  收藏代码
@Override 


示例4,成员为字符串数组的注解:
Java代码  收藏代码
@SuppressWarnings(value={"unchecked","fallthrough"}) 


示例5,成员为注解数组类型的注解:
Java代码  收藏代码
@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是枚举类型的成员。

由于NeedTest注解的保留限期是RetentionPolicy.RUNTIME类型,因此当ForumService被加载到JVM时,仍就可通过反射机制访问到ForumService各方法的注解信息。

访问注解

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

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

下面,我们就通过反射来访问注解,得出ForumService 类中通过@NeedTest注解所承载的测试需求,如代码清单7-3所示:

代码清单7-3  TestTool:访问代码中的注解
Java代码  收藏代码
package com.baobaotao.aspectj.anno; 
import java.lang.reflect.Method; 
public class TestTool { 
    public static void main(String[] args) { 
                 
               //①得到ForumService对应的Class对象 
        Class clazz = ForumService.class;  
 
                //②得到ForumSerivce对应的Method数组 
        Method[] methods = clazz.getDeclaredMethods();  
 
        System.out.println(methods.length); 
        for (Method method : methods) { 
 
                        //③获取方法上所标注的注解对象 
            NeedTest nt = method.getAnnotation(NeedTest. class); 
            if (nt != null) { 
                if (nt.value()) { 
                    System.out.println(method.getName() + "()需要测试"); 
                } else { 
                    System.out.println(method.getName() + "()不需要测试"); 
                } 
            } 
        } 
    } 
分享到:
评论

相关推荐

    JDK8注解应用例子

    5. `@Repeatable`(JDK8新增):允许一个注解在同一位置被多次使用。之前版本中,如果需要多次使用同一注解,需要自定义容器注解,而现在可以直接通过此元注解实现。 二、预定义注解 JDK8对一些预定义注解进行了...

    JDK 1.8中文API文档

    JDK 1.8中文API文档详细列出了所有Java 1.8提供的类库、接口、枚举、注解等,包括它们的方法、属性和构造器,是学习和查阅Java 1.8特性的必备参考资料。通过查阅该文档,开发者可以快速找到所需的类和方法,理解其...

    JDK8 API 中文 文档.CHM

    **JDK8 API中文文档**是Java开发人员的重要参考资料,它包含了Java Development Kit(JDK)8版本的所有公共类、接口、枚举和注解的详细说明。这个文档以CHM(Compiled Help Manual)格式提供,是一种常见的Windows...

    最新版jdk 8【百度网盘】

    8. **类型注解**:JDK 8允许在类型上使用注解,增强了元数据的表达能力,对编译器和静态分析工具有很大帮助。 9. **并行收集器**:在垃圾回收(GC)方面,JDK 8引入了G1垃圾收集器,这是一个强大的并发标记清除算法...

    jdk1.8中文开发文档

    集合接口如`List`, `Set`, `Map`新增了工厂方法,如`of()`, `ofNullable()`, `copyOf()`, 使创建不可变集合变得更加简单且安全。 9. ** Nashorn JavaScript引擎** JDK 1.8引入了一个内置的JavaScript引擎,名为...

    JDK 6.0.zip

    7. **元注解**:元注解的引入使得开发者可以在编译时或运行时处理注解,扩展了注解的使用范围。 8. **并发工具**:提供了一套新的并发工具类,如`ConcurrentHashMap`、`CyclicBarrier`和`Phaser`等,帮助开发者更好...

    jdk 1.8中文版chm

    8. **类型注解**:增加了类型注解的支持,可以对泛型类型、参数、返回值等进行注解,增强了代码的元数据信息,有助于编译器和工具进行类型检查和静态分析。 9. **Optional类**:为了减少空指针异常,引入了`...

    1.0 jdk.rar

    - 1.0版本的API相对有限,许多现代Java特性如泛型、枚举、注解、Lambda表达式等都是后来版本新增的。 - 类库的规模较小,许多库和框架(如Spring、Hibernate)在后续版本中出现。 - 性能方面,现代JDK进行了大量...

    JDK_API_1.8(中文版)JDK_API_1_8_zh_CN.zip

    2. 集合框架:Java 1.8对集合框架进行了优化,如`ArrayList`和`HashMap`的性能提升,以及`Set`接口新增`removeIf()`方法,允许基于谓词进行元素删除。 3. 并发编程:`java.util.concurrent`包中,`ForkJoinPool`和`...

    jdk-8u281-windows-x64.rar

    8. **改进的枚举和注解**:JDK 8增加了对枚举类型的默认方法支持,并且增强了注解的元注解,使得注解在框架设计和元编程中的应用更加广泛。 9. **并行GC优化**:JDK 8对垃圾收集器进行了优化,如G1(Garbage-First...

    java的jdk6安装包

    6. 并发编程改进:`java.util.concurrent`包新增多个并发工具类,如`ExecutorService`、`Future`和`CountDownLatch`等。 四、Java 6与其他版本的区别 Java 6相较于Java 5,主要改进了性能和开发者体验,而后续的...

    jdk1.6 chm文档

    2. **新增特性**:JDK 1.6相对于之前的版本,引入了一些新的特性和改进。例如,`java.util.concurrent`包得到了极大的扩展,增加了许多并发工具类,如`ExecutorService`和`Future`,提高了多线程编程的效率和安全性...

    jdk11官网下载 linux+windows

    7. **动态类型**:JEP 330允许在注解中使用`@TypeUse`和`@TargetType`。 五、JDK11的使用 JDK11包含JRE(Java Runtime Environment)和一系列开发工具,如`javac`(Java编译器)、`javadoc`(文档生成器)和`jar`...

    jdk-11.0.10.rar

    Java Development Kit(简称JDK)是Oracle公司发布的用于开发和运行Java应用程序的工具包,它包含了Java编译器、Java虚拟机(JVM)、Java类库以及一些开发工具。在这个场景中,我们讨论的是JDK的第11个主要版本,即...

    jdk-7u80-docs-all.zip

    5. 类注解处理器:Java注解处理器框架允许在编译时自定义处理注解,增强了元编程的能力。 四、文档结构与使用 JDK 1.7u80的文档通常包含以下部分: - 类和接口的详细描述:列出所有核心类和接口,包括构造函数、...

    jdk-8u91-windows-x64.zip

    JDK1.8还新增了一些内置的函数式接口,如`Supplier`、`Consumer`、`Function`等。 4. ** 接口默认方法**:JDK1.8允许在接口中定义默认方法,提供默认实现,这样可以为已有的接口添加功能而不破坏已有实现。 5. ** ...

    jdk1.8 64位

    Stream API是Java 8中新增的数据处理模型,提供了序列化操作数据的方式,可以进行过滤、映射、聚合等操作。Stream API与集合紧密集成,极大地简化了大量数据的处理过程。 4. **Method References** 方法引用是另...

    JDK --java

    JDK 8增加了类型注解,允许在类型声明(包括参数、返回值、字段和数组元素类型)上使用注解,增强了代码的元数据信息,有助于工具和库进行类型检查和验证。 **10. 并发更新** 在JDK 8中,`ConcurrentHashMap`得到了...

    最新版本JDK

    JDBC(Java Database Connectivity)在JDK 1.8中也有所增强,比如增加了4.1版本,支持更多数据库特性,如SQL注解和结果集的滚动。这使得Java应用程序与数据库之间的交互更为灵活和强大。 在日期和时间API上,JDK ...

    java jdk9 windows x64免安装版(openjdk9.0.4)

    此外,JDK 9增强了Javadoc,新增了`@implNote`、`@implSpec`和`@implDefault`注解,这些注解为实现者提供了更多的文档空间,以记录实现细节和非API规范。同时,JShell(也称为Read-Eval-Print Loop,简称REPL)作为...

Global site tag (gtag.js) - Google Analytics