`
metaphy
  • 浏览: 344049 次
  • 性别: Icon_minigender_1
  • 来自: 大西洋底
社区版块
存档分类
最新评论

Java5.0的注解(Annotations)

阅读更多

声明
本译文同步发表在译言“软件设计与开发”小组,“软件设计与开发”小组关注软件设计思想,软件开发模式等最新前沿文章的翻译,有兴趣的请加入。

 许多API都需要为数不少的“模板式”的代码,比如,如果想写一个JAX-RPC(JAX-RPC即Java API for XML-Based RPC-译注)的web service,你需要提供一对接口及其实现程序。如果程序本身能被表明哪些方法可以由远程访问的注释所“修饰”的话,那么这种“模板式”的代码就可以用工具自动生成。

另一些API需要在维护程序的同时维护一些“辅助”文件,比如,维护JavaBean的同时需要维护BeanInfo类,Enterprise JavaBeans (EJB) 则需要部署说明档(deployment descriptor)。如果这些辅助信息能在程序中作为注解来维护,就会方便地多,并且也不容易犯错。

Java平台已经提供了几种不同的注解机制。比如transient修饰符就是一种特别的注解,标明被修饰的字段在序列化的子系统应该被忽略,@deprecated 作为javadoc的特殊标签,标明该方法不应该再用。在5.0版本中,Java平台提供了一种一般性的注解(即元数据metadata)机制,允许你自定义注解类型和使用该类型。该机制包含注解的定义语法、声明语法、读取注解的API、注解的代理类文件以及注解的一个处理工具。

注解并不直接对程序语义产生影响,但是会对工具或库在处理程序的方式上时产生影响,进而影响程序在运行时的语义。注解可以从源文件或类文件中读取,甚至在运行时以反射方式读取。

注解是对javadoc标签的补充。一般而言,如果标注的目的是影响或产生文档,那么就该用javadoc标签,否则就用注解。典型的应用程序的程序员永远不必自己定义一个注解类型,但其实真要做也不难。注解类型的定义跟接口定义相似,只是需要在inteface关键字前面加一个at符(@),声明一个方法即为注解类型定义一个元素。方法声明时不允许有参数或throw语句,返回值类型被限定为原始数据类型、字符串String、Class、枚举enums、注解类型,或前面这些的数组,方法可以有默认值,下面是一个定义注解类型的例子:

/**
 * Describes the Request-For-Enhancement(RFE) that led
 * to the presence of the annotated API element.
 */
public @interface RequestForEnhancement {
    int    id();
    String synopsis();
    String engineer() default "[unassigned]"; 
    String date();    default "[unimplemented]"; 
}

一旦完成定义,就可以使用它做注解声明。注解是一个特殊的修饰符,可以和其他修饰符一样(如public,static,final)用在各种地方。为方便计,注解一般放在最前面。注解修饰符由@符号、注解类型名和括号括起来的元素名/值对组成。下面这个例子声明一个方法使用了上面所定义的注解。

@RequestForEnhancement(
    id       = 2868724,
    synopsis = "Enable time-travel",
    engineer = "Mr. Peabody",
    date     = "4/1/3007"
)
public static void travelThroughTime(Date destination) { ... }

注解类型如果不含任何元素,被称为“标记”注解类型,如:

/**
 * Indicates that the specification of the annotated API element
 * is preliminary and subject to change.
 */
public @interface Preliminary { }

“标记”注解类型允许忽略括号,如下:

@Preliminary public class TimeTravel { ... }

如果注解只有一个元素,那么该元素应该被命名为value,如下:

/**
 * Associates a copyright notice with the annotated API element.
 */
public @interface Copyright {
    String value();
}

如果注解只有一个元素,并且元素名为value,那么元素名和等号(=)都可以忽略不写,如下:

@Copyright("2002 Yoyodyne Propulsion Systems")
public class OscillationOverthruster { ... }

我们将建一个简单的基于注解的测试框架,将前面所讲的合起来用。首先我们定义一个“标记”注解类型,来说明某个方法是一个测试方法,需要被测试工具执行:

import java.lang.annotation.*;

/**
 * Indicates that the annotated method is a test method.
 * This annotation should be used only on parameterless static methods.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test { }

注意这个注解本身也是被注解的。这些注解被称为“元注解” (meta-annotations). 第一个(@Retention(RetentionPolicy.RUNTIME)) 表示注解由虚拟机保留,可以在运行时通过反射读取;第二个(@Target(ElementType.METHOD)) 表示注解只能用在方法上。

下面是一个例子程序,其中的一些方法由上面所定义的注解来修饰:

public class Foo {
    @Test public static void m1() { }
    public static void m2() { }
    @Test public static void m3() {
        throw new RuntimeException("Boom");
    }
    public static void m4() { }
    @Test public static void m5() { }
    public static void m6() { }
    @Test public static void m7() {
        throw new RuntimeException("Crash");
    }
    public static void m8() { }
}

下面是测试工具程序:

import java.lang.reflect.*;

public class RunTests {
   public static void main(String[] args) throws Exception {
      int passed = 0, failed = 0;
      for (Method m : Class.forName(args[0]).getMethods()) {
         if (m.isAnnotationPresent(Test.class)) {
            try {
               m.invoke(null);
               passed++;
            } catch (Throwable ex) {
               System.out.printf("Test %s failed: %s %n", m, ex.getCause());
               failed++;
            }
         }
      }
      System.out.printf("Passed: %d, Failed %d%n", passed, failed);
   }
}

这个工具程序将一个类名作为命令行运行时的参数,然后遍历该类的所有方法,并尝试调用每一个被“Test”注解(就是上面所定义的)所修饰的方法。那行绿色的代码以反射调用方式查找方法是否被“Test”注解所修饰。如果调用测试方法时抛出异常,就认为测试失败,测试失败的信息就会打印出来。最后作为总结,测试失败的方法个数和测试成功的方法个数也会打印出来。下面是对Foo程序(就是上面那个)运行测试工具得到的结果:

$ java RunTests Foo
Test public static void Foo.m3() failed: java.lang.RuntimeException: Boom 
Test public static void Foo.m7() failed: java.lang.RuntimeException: Crash 
Passed: 2, Failed 2

这个测试工具无疑是个玩具程序,但它表明了注解的强大,并能很容易的扩展为一个有用的工具。

2
0
分享到:
评论

相关推荐

    Java5.0中方帮助文档

    这份"Java5.0中方帮助文档"是针对中国开发者量身定制的官方指南,包含了丰富的API详解、示例代码和编程指南,对于Java初学者和资深开发者来说都是宝贵的资源。 1. **泛型(Generics)** Java 5.0引入了泛型,允许...

    Java API_5.0中文版

    3. **注解(Annotations)**:注解是元数据的一种形式,提供了一种安全的方法来将信息附加到代码上,而不会影响代码的运行时行为。注解可以用于编译器检查、运行时处理、代码生成等场景。例如,@Override标记表示...

    Java 5.0 Tiger程序高手秘笈.rar

    注解是Java 5.0引入的另一项重要特性,提供了一种元编程的方法,允许在源代码中插入元数据。注解可以被编译器或JVM读取,用于配置编译过程、执行时行为或生成文档等。 八、内省增强(Improved Introspection) Java...

    Java5.0 Tiger程序高手秘笈(含源码)

    本书《Java5.0 Tiger程序高手秘笈》正是为了帮助开发者掌握这些新特性而编写,结合源码分析,将有助于深入理解Java 5.0的核心改进。 1. **泛型**:Java 5.0引入了泛型,这是一种类型安全机制,允许在编译时检查类型...

    Java5.0中文API

    这个"Java5.0中文API"显然是一份中文版的Java 5.0标准类库文档,它详细地阐述了Java 5.0中的各种类、接口、方法和异常,是Java开发者的重要参考资料。 1. **泛型**:Java 5.0引入了泛型,这是一种在编译时检查类型...

    JAVA5.0API

    在《JAVA5.0API_CN.CHM》文档中,你可以找到所有这些特性的详细描述以及如何使用它们的例子。每个类、接口和方法都有详细的解释,包括它们的作用、返回值、参数以及可能抛出的异常。此外,文档还提供了丰富的示例...

    良葛格java5.0的学习笔记

    4. **Annotations(注解)**:注解是一种元数据,可以提供编译器或运行时系统使用的信息。它们可以用于代码分析、代码生成、测试验证等,大大简化了代码维护和管理。 5. **Enhanced for loop(增强for循环)**:也...

    JAVA 5.0 TIGER程序高手秘笈

    此外,Java 5.0引入了变量注解(annotations),这是一种元数据,用于向编译器或运行时环境提供信息。通过注解,开发者可以自定义元数据,实现代码的自动化处理,如代码生成、验证、调试等。Java标准库中的一些注解...

    java 5.0 API 文档 参考册 chm格式

    Java 5.0还引入了注解(Annotations),这是一种元数据,可以在源代码中插入用于工具或编译器处理的信息。注解可用于编译时检查、运行时处理、代码生成等场景。例如,@Override标记确保方法确实重写了超类的方法,@...

    JAVA5.0API_CN

    Java 5.0引入了注解,这是一种元数据,提供了在代码中添加元信息的方式。注解可以用于编译时检查或运行时处理,如Spring框架中的@Component注解。例如: ```java @Deprecated public void oldMethod() { // ... } ...

    《Java5.0 Tiger》书籍源码

    6. 另外,书中可能还涵盖了其他Java 5.0的重要特性,如注解(Annotations),它为元数据提供支持,可以用于编译时和运行时的处理;类型安全的枚举(Enums),使得枚举类型更加安全和强大;以及并发处理的改进,如...

    Java5.0 Tiger全书代码.rar

    这个"Java5.0 Tiger全书代码.rar"压缩包包含的是《Java5.0 Tiger程序员高手秘笈》这本书的配套源码,这是一本深受Java开发者喜爱的进阶指南,旨在帮助读者深入理解Java 5.0的新特性和最佳实践。 首先,Java 5.0的...

    Java5.0Tiger程序高手秘笈PDF.rar

    3. **变量注解(Annotations)**:Java 5.0引入了注解,这是一种元数据,可以用于在代码中添加信息,供编译器、工具或运行时系统使用,如@Override、@Deprecated等。 4. **自动装箱与拆箱(Autoboxing/Unboxing)**...

    Java JDK 5.0学习笔记

    Java 5.0引入了@符号来定义注解,如@Override用于标记重写的方法,@Deprecated表示某个方法或类已废弃。注解可以被编译器或运行时环境用于验证、生成代码、持久化元数据等。 五、增强的for循环(Enhanced For Loop...

    java5.0新特性

    3. **注解(Annotations)**:注解是一种元数据,提供了一种安全地将信息附加到代码的方式,而不会影响代码的运行。注解可以用于编译器检查、编译时处理或运行时反射,如@Override、@Deprecated和@Autowired等。 4....

    Java5.0 Tiger程序高手秘笈

    4. **变量注解(Variable Annotations)**:Java 5.0允许在变量声明上使用注解,这对于元数据的处理和代码的验证非常有用。 5. **可变参数(Varargs)**:通过`...`语法,开发者可以创建接受不定数量参数的方法,...

    JAVA5.0新特性讲解与例子

    7. **注解(Annotations)** 注解是一种元数据,提供了在代码中插入元信息的方式,用于编译器、JVM或工具使用。例如,`@Override` 检查方法是否真正覆盖了超类的方法,`@Deprecated` 标记已过时的API。 8. **内省...

    javaAPI 5.0中文.rar,javaAPI 5.0中文.rar

    5. **变量注解(Annotations)**:这是一种元数据,可以向编译器或JVM提供关于代码的附加信息。例如,@Override表示方法是重写父类方法,@Deprecated标记过时的API。 6. **可变参数(Varargs)**:在方法签名中,...

Global site tag (gtag.js) - Google Analytics