Java之注解篇

来源:互联网 发布:图书数据 编辑:程序博客网 时间:2024/05/22 13:39

了解注解

我们有必要对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表示关闭一些不当的编译器警告信息。


1、与注释的区别:
注释:描述代码的文字
即:这种注释只是需要给人看,而机器本身并不会执行
 
注解:描述代码的代码
即:注解不仅仅是给人看,而且机器本身也会将其作为代码执行
 
2、注解的作用:
规定某个方法的作用,用于检查某个方法的定义是否起到了注解中规定的作用,例如:
 
@Override                            //规定下一个方法的作用为覆盖父类里的方法
public String toStirng {          //在此处拼错了toString
  return "Success!";
}                                          //则编译出错
 
3、注解的本质:注解是一种类型
JDK5.0中的类型:1、类(class)2、接口(interface)3、枚举(enum)4、注解(Annotation)
因此,注解与其他3种类型一样,都可以定义、使用,以及包含有自己的属性、方法
 
4、注解的分类:
(1)标记注释:注解的内部没有属性,称作标记注解
使用方法:@注解名
使用例子:@MarkAnnotation
 
(2)单值注解:注解的内部只有一个属性,称作单值注解
使用方法:@注解名(属性名=属性值)
使用例子:@SingleAnnotation(value="abc")  //也可以写成@SingleAnnotation("abc")
*(属性名=属性值)可以简化为(属性值),但是需要满足以下两个条件:
1、该注解必须为单值注解
2、该注解的属性名必须为value
 
(3)多值注解:注解的内部有多个属性,称作多值注解
使用方法:@注解名(属性名1=属性值1, 属性名2=属性值2……)
使用例子:@MultipliedAnnotation(value1 = "abc", value2 = 30……)
 
/*********以下内容为扩展知识*********/
 
5、自定义注解:
用途:用于开发人员在开发程序的过程中测试指令
 
***********分界线:测试人员的测试步骤**********
 
测试步骤:
1、写出一个测试类
2、在主方法中创建一个需要测试的对象
3、由于需要被测试的对象某些方法不能被调用,而某些方法又不需要被调用(即:需要被测试的对象仅仅有某些方法需要被调用),因此程序的开发人员需要通过注释来通知测试人员哪些方法需要被调用
4、由于测试的时候需要使用临界测试点来测试程序(即:使用最容易使程序出错的参数来测试程序),因此程序的开发人员需要通过注释来通知测试人员什么样的参数为程序的临界测试点
*测试的目的:尽可能发现程序中的错误,而不是证明程序的正确性
 
*****************分界线结束****************
 
因此,由于需要被测试的方法以及临界测试点都是需要由开发人员通过注释来通知测试人员的,因此开发人员可以通过使用Annotation来直接通知虚拟机来对程序进行测试,而不再需要测试人员
 
定义注解的语法:
public @interface TestCase {  //注意在这里使用的是@interface而不是@class
  String value() ;
  //定义该注解的属性(注意注释中的属性和方法是不区分的,每一个元素既是属性,也是方法,因此上句也可以被理解成方法的定义)
 
  String value() default "TestValue";
  //定义该注解的属性时,定义默认的属性值
}
 
 
6、元注解:系统提供的注解,用于注解自定义注解
元注解理解:
注解可以用于注解类(annotate Classes)
可以用于注解接口(annotate Interfaces)
可以用于注解枚举类型(annotate Enums)
因此注解同样也可以用于注解注解(annotate Annotations)
 
(1)@Target注解:
@Target注解是一个单值注释,唯一的属性名为value
value类型:ElementType的数组
 
*ElementType
ElementType是一个枚举类型,它在其中定义了
ANNOTATION_TYPE    注释
CONSTRUCTOR           构造方法
FIELD                          成员变量
LOCAL_VARIABLE      局部变量
METHOD                     方法
PACKAGE                    包
PARAMETER               参数
TYPE                           类型(?)
 
定义方法:@Target (value = {METHOD, FIELD, ...})
@Target的作用:表示该自定义注释写出来后能够注释什么元素类型(能够注解的元素类型,就是在定义@Target时value数组中的值(ElementType类型))
 
(2)@Retention注解:
@Retention注解是一个单值注释,唯一的属性名为value
value类型:RetentionPolicy类型
 
*RetentionPolicy
RetentionPolicy是一个枚举类型,它在其中定义了
SOURCE  表示该自定义注释仅仅是提供给编译器对程序进行检查的依据,在编译的过程中,该自定义注释就会被清除掉(即:不会被保存到.class文件中)
 
CLASS  表示该自定义注释会在.class文件中保留,但是当该.class文件被加载到虚拟机(产生类对象)的时候,该注释就会被清除掉(即:不会被加载到虚拟机中)
 
RUNTIME  表示该自定义注释不会被忽略,仅有此种类型的注释会被保留到运行时,并可以在类对象中察看
定义方法:@Retention (value = SOURCE/CLASS/RUNTIME)
@Retention的作用:表示该自定义注释会被保留到什么时候(能够保留到的时候,就是在定义@Rentention的时候value中的值(RetentionPolicy类型))
 
7、自动测试机的写法:
自动测试机的原理:
使用Annotation来Annotate元素的实质是:每一个ElementType内部的元素都有两个方法,分别为
(注:为方便理解,以下使用的TestCase为某个特定的自定义注释)
(1)isAnnotationPresent(TestCase.class)  //判断该元素是否被TestCase所注释
(2)getAnnotation(TestCase.class)  //获得TestCase的类对象
 
因此,自动测试机的工作过程是:
(1)首先通过反射,获得被测类o中的每一个方法
(2)对每一个方法通过使用isAnnotationPresent(TestCase.class)判断其是否被TestCase所注释(注意是.class!)
(3)如果某方法method被TestCase所注释,则通过method的getAnnotation(TestCase.class)获得TestCase的类对象tc
(4)通过tc的value()方法,获得该类对象的属性value
(注:此处使用的value()方法,正是在TestCase中定义的value属性,再次理解在注释中定义的value既是属性,也是方法
(5)调用method方法的invoke(o,value),用value对method进行测试
 
8、注解使用实例:
要求:
(1)定义一个单值注解TestCase,使其可以注解方法,并且可以被保留到程序运行时
注解的属性类型为String,要求可以使用简写方式为属性赋值
(2)定义一个类MyClass,要求有三个方法Method1、2、3
方法的参数、返回值类型均为String类型,返回值为传入的参数
使用(1)中的注解来注释Method1、3,并对属性参数赋值
(3)定义一个测试类TestMyClass,要求使用反射来测试MyClass中所有的被TestCase注解的方法
并将注解的属性值作为参数,调用相应方法来返回测试结果
 
例子:
---------------------------1---------------------------
 
import java.lang.annotation.*;
 
@Target ({ElementType.METHOD})
@Retention (RetentionPolicy.RUNTIME)
 
public @interface TestCase {
  String value();
}
 
---------------------------2---------------------------
 
public class MyClass {
  @TestCase("This is Method 1")
  public String Method1 (String s) {
    return s;
  }
 
  public String Method2 (String s) {
    return s;
  }
 
  @TestCase("This is Method 3")
  public String Method3 (String s) {
    return s;
  }
}
 
---------------------------3---------------------------
 
import java.lang.reflect.*;
 
public class TestMyClass {
  public static void main(String [] args) {
    Class c = Class.forName("MyClass");
    Method [] ms = c.getDeclaredMethods();
    for (Method m : ms) {
      if(m.isAnnotationPresent(TestCase.class) {
        TestCase tc = m.getAnnotation(TestCase.class);
        Object o = c.newInstance();
        String s = tc.value();
        m.invoke(o, s);
        或者以上三句可以直接写成:
        m.invoke(c.newInstace, tc.value());
      }
    }
  }
}


0 0
原创粉丝点击