黑马程序员---Java注解Annotations的详解以及使用实例

 ------- android培训java培训、期待与您交流! ----------

  • 许多Api需要相当数量的样板代码。比如,为了写一个JAX-RPC网络服务。你必须提供一个成对的接口和实现,如果程序用注解装饰来表明哪个方法是远程可调用的那么这个样板代码就可以被一个工具自动生成。
  • 其他API需要“副文件”同时被维护。例如,JavaBeans需要一个BeanInfo类来和这个Bean同时维护,企业级的JavaBeans (EJB)需要一个部署描述符。如果通过注解用程序本身来维护这些副文件那么就会更方便也不容易出现错误。
  • Java平台总是会有各种各样的特别的注解机制。比如短暂性修饰符就是一个特殊的注解表明一个域应该被序列化子系统忽略,@deprecated javadoc标记也是一个特殊的注解表明方法不应该在被使用了。Java平台提供了一些通用的目标注解(也就是元注解)机制允许你定义和使用你自己的注解类型。这个机制由一个声明注解类型语法和一个使用注解类型注解的语法组成。读取注解的API和注解处理由javac 工具提供支持。注释由类文件表示。
  • 注解不会直接影响程序的语义,但是他们会影响程序被工具和库处理的方式,进而反过来影响运行程序的语义。注解可以从源文件读出类文件读出或在运行时反射。
  • 注解补充了Javadoc标记。一般来说如果标记目的是影响或处理文档,它很可能是一个javadoc标记,否则就是一个注解。
  • 一般的应用程序开发者将永远不必定义一个注解类型,但是定义一个注解也不是很困难。注解类型的定义类似于普通的接口定义。把一个@符号放在interface关键词之前,里面的每一个方法声明定义了这个注解类型的元素。方法声明必须不能有任何参数也不能有抛出语句。返回类型限制在原始类型String, Class, enums, annotations,和前面类型的数组。方法可以有默认值。下面是一个注解类型的定义:

 

/**
 * 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 { ... }

 

  • 如果注解只有一个元素那么元素不能有默认值,如下所示:

 

/**
 * Associates a copyright notice with the annotated API element.
 */
public @interface Copyright {
    String 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 { }

 

  • 注意注解类型的定义是自我注释的。这样的注解就是元注解。第一个@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注解注释的方法(上面定义)。反射的查询是否一个方法有注解定义存在。如果一个测试方法调用抛出了异常,这个测试方法就失败了,打印失败报告。最终打印成功的和失败的方法数。下面是在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

  • 很明显这个测试工具是一个玩具程序,它演示了注解的力量并且可以很容易的被扩展以克服它的局限性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值