`
kungstriving
  • 浏览: 129201 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java5中的注解功能(Annotation)

    博客分类:
  • Java
阅读更多

注解(Annotation)是Java5中的新特性,一直看到很多项目在使用,但是自己一直不是很了解,现在有机会学习了一下,记录下来,今后用得着。

1.注解可以做什么?

注解将一些系统所需的数据信息(不方便用Java语言来表达),加入到了Java源代码中,而不需要额外的信息提供者。比如配置信息、一些样板文件(接口文件)等。可以通过在代码中添加注解,来直接配置你的系统。

著名的Java单元测试框架Junit-4就是大量使用了注解的功能,加入到了其单元测试中,方面了用户使用JUnit进行测试,用户只需要在想要测试的方法上添加@Test 这样的标签就可以将该方法变为一个单元测试用例。

下面,我将仿照JUnit的测试框架来简单介绍一下注解功能(例子来自于java.sun.com)

2.注解怎么使用

我把注解的使用分为三个步骤:

第一,定义注解

第二,给源程序添加注解

第三,解析注解(实际工作在这里完成)

 

首先看定义注解

 

注解的定义看起来和定义接口差不多,就是在interface关键字前多一个@标签

 

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

 其中的id()、synopsis()可以认为是该注解的元素,或者属性,这些方法声明不能有任何参数,或者抛出异常,可以通过default 来定义它的默认值。而且这些类型只能是原语类型、String、Annotation或者这些类型的数组。

最上面的@Target表面了改注解使用的范围(是一个方法还是一个类,或者一个域),@Retention表面了注解可以用在哪个级别上(源代码中、类文件中、还是运行时)

 

这样,便定义了一个注解

 

接下来给源程序添加注解:

 

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

 

 这样就使用刚才定义的RequestForEnhancement注解,描述了一个方法,可以看见在()中,定义了给该注解的各个元素的参数,就相当于初始化了该注解

 

最后解析注解,这里我们使用一个简单的测试框架来表述

定义一个Test注解,使用在运行时,定义在方法上,它没有任何方法,只是一个标注

在解析程序中,获取该标注,并采取相应动作。在这里,使用了Test标签标注的方法,都将被测试,并形成测试结果。

 

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 { }

 

添加将被测试的方法:

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() { }
}

 

在这里用@Test标签标注了m1 m3 m5 m7方法,这些方法将在运行测试用例时被测试。

在该类中运行了测试用例,它使用反射机制,调用了被标注为@Test标签的方法,如果抛出异常则认为测试没有通过,反之则通过。

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);
   }
}

 

在这里,可以讲上面的这些类、注解可以和JUnit中的进行一个对比

@Test就是JUnit框架中的@Test

被标注的方法将被测试

RunTest类就相当于手动启动JUnit进行单元测试时运行的org.junit.runner.JUnitCore.runClasses(不是使用IDE启动测试用例,如果使用Eclipse类似的IDE,你可能只是点击一个Run As JUnit)

 

这样,就通过注解完成了一个简单的测试框架

 

详细信息可以查看

http://java.sun.com/j2se/1.5.0/docs/guide/language/annotations.html

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics