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

java5.0注释详解

阅读更多

一、什么是注释

    说起注释,得先提一提什么是元数据(metadata)。所谓元数据就是数据的数据。也就是说,元数据是描述数据的。就象数据表中的字段一样,每个字段描 述了这个字段下的数据的含义。而J2SE5.0中提供的注释就是java源代码的元数据,也就是说注释是描述java源代码的。在J2SE5.0中可以自 定义注释。使用时在@后面跟注释的名字。
                                                                                    
二、J2SE5.0中预定义的注释


    在J2SE5.0的java.lang包中预定义了三个注释。它们是Override、Deprecated和SuppressWarnings。下面分别解释它们的含义。

Override

    这个注释的作用是标识某一个方法是否覆盖了它的父类的方法。那么为什么要标识呢?让我们来看看如果不用Override标识会发生什么事情。

    假设有两个类Class1和ParentClass1,用Class1中的myMethod1方法覆盖ParentClass1中的myMethod1方法。

            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->class ParentClass1 ... { public void myMethod1() ... {...} } class Class1 extends ParentClass1 ... { public void myMethod2() ... {...} }
建立Class1的实例,并且调用myMethod1方法
            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->ParentClass1 c1 = new Class1(); c1.myMethod1();
以上的代码可以正常编译通过和运行。但是在写Class1的代码时,误将myMethod1写成了myMethod2,然而在调用时,myMethod1 并未被覆盖。因此,c1.myMethod1()调用的还是ParentClass1的myMethod1方法。更不幸的是,程序员并未意识到这一点。因 此,这可能会产生bug。

   如果我们使用Override来修饰Class1中的myMethod1方法,当myMethod1被误写成别的方法时,编译器就会报错。因此,就可以避免这类错误。

            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->class Class1 extends ParentClass1 ... {  @Override // 编译器产生一个错误 public void myMethod2() ... {...} }
以上代码编译不能通过,被Override注释的方法必须在父类中存在同样的方法程序才能编译通过。也就是说只有下面的代码才能正确编译。

            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->class Class1 extends ParentClass1 ... { @Override public void myMethod1() ... {...} }

Deprecated

    这个注释是一个标记注释。所谓标记注释,就是在源程序中加入这个标记后,并不影响程序的编译,但有时编译器会显示一些警告信息。
   
    那么Deprecated注释是什么意思呢?如果你经常使用eclipse等IDE编写java程序时,可能会经常在属性或方法提示中看到这个词。如果某 个类成员的提示中出现了个词,就表示这个并不建议使用这个类成员。因为这个类成员在未来的JDK版本中可能被删除。之所以在现在还保留,是因为给那些已经 使用了这些类成员的程序一个缓冲期。如果现在就去了,那么这些程序就无法在新的编译器中编译了。

    说到这,可能你已经猜出来了。Deprecated注释一定和这些类成员有关。说得对!使用Deprecated标注一个类成员后,这个类成员在显示上就会有一些变化。在eclipse中非常明显。让我们看看图1有哪些变化。


图1 加上@Deprecated后的类成员在eclipse中的变化



    从上图可以看出,有三个地方发生的变化。红色框里面的是变化的部分。
    1. 方法定义处
    2. 方法引用处
    3. 显示的成员列表中

    发生这些变化并不会影响编译,只是提醒一下程序员,这个方法以后是要被删除的,最好别用。

    Deprecated注释还有一个作用。就是如果一个类从另外一个类继承,并且override被继承类的Deprecated方法,在编译时将会出现一个警告。如test.java的内容如下:

            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->class Class1 ... { @Deprecated public void myMethod() ... {} } class Class2 extends Class1 ... { public void myMethod() ... {} }
1
1
运行javac test.java 出现如下警告:

    注意:test.java 使用或覆盖了已过时的 API。
    注意:要了解详细信息,请使用 -Xlint:deprecation 重新编译
    使用-Xlint:deprecation显示更详细的警告信息:

    test.java:4: 警告:[deprecation] Class1 中的 myMethod() 已过时

    public void myMethod()
    ^
    1 警告

    这些警告并不会影响编译,只是提醒你一下尽量不要用myMethod方法。

    SuppressWarnings


    这个世界的事物总是成对出现。即然有使编译器产生警告信息的,那么就有抑制编译器产生警告信息的。
    SuppressWarnings注释就是为了这样一个目的而存在的。让我们先看一看如下的代码。

            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->public void myMethod() ... { List wordList = new ArrayList(); wordList.add( " foo " ); }
这是一个类中的方法。编译它,将会得到如下的警告。

    注意:Testannotation.java 使用了未经检查或不安全的操作。
    注意:要了解详细信息,请使用 -Xlint:unchecked 重新编译。

    这两行警告信息表示List类必须使用范型才是安全的,才可以进行类型检查。如果想不显示这个警告信息有两种方法。一个是将这个方法进行如下改写:
1

public void myMethod()
{
  List<String> wordList = new ArrayList<String>();
  wordList.add("foo");
}

另外一种方法就是使用@SuppressWarnings。
@SuppressWarnings (value={"unchecked"})
public void myMethod()
{
  List wordList = new ArrayList();
  wordList.add("foo");
}
要注意的是SuppressWarnings和前两个注释不一样。这个注释有一个属性。当然,还可以抑制其它警告,如:
@SuppressWarnings (value={"unchecked", "fallthrough"})

三、如何自定义注释

    注释的强大之处是它不仅可以使java程序变成自描述的,而且允许程序员自定义注释。注释的定义和接口差不多,只是在interface前面多了一个“@”。

            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->public @interface MyAnnotation ... { }
上面的代码是一个最简单的注释。这个注释没有属性。也可以理解为是一个标记注释。就象Serializable接口一样是一个标记接口,里面未定义任何方法。

    当然,也可以定义有属性的注释。
            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->public @interface MyAnnotation ... {   String value(); }
可以按如下格式使用MyAnnotation
            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->@MyAnnotation("abc") public void myMethod() ... { }
看了上面的代码,大家可能有一个疑问。怎么没有使用value,而直接就写”abc”了。那么”abc”到底传给谁了。其实这里有一个约定。如果没有写属 性名的值,而这个注释又有value属性,就将这个值赋给value属性,如果没有,就出现编译错误。

    除了可以省略属性名,还可以省略属性值。这就是默认值。
            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->public @interface MyAnnotation ... {   public String myMethod() ... {} default “xyz”; }
可以直接使用MyAnnotation
            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->@MyAnnotation // 使用默认值xyz public void myMethod() ... { }
也可以这样使用
            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->@MyAnnotation(myMethod = ”abc”) public void myMethod() ... { }

    如果要使用多个属性的话。可以参考如下代码。
            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->public @interface MyAnnotation ... { public enum MyEnum ... {A, B, C} public MyEnum.value1() ... {} public String value2() ... {} } @MyAnnotation(value1 = MyAnnotation.MyEnum.A, value2 = “xyz”) public void myMethod() ... { }
这一节讨论了如何自定义注释。那么定义注释有什么用呢?有什么方法对注释进行限制呢?我们能从程序中得到注释吗?这些疑问都可以从下面的内容找到答案。
1



四、如何对注释进行注释


    这一节的题目读起来虽然有些绕口,但它所蕴涵的知识却对设计更强大的java程序有很大帮助。
在上一节讨论了自定义注释,由此我们可知注释在J2SE5.0中也和类、接口一样。是程序中的一个基本的组成部分。既然可以对类、接口进行注释,那么当然也可以对注释进行注释。
    使用普通注释对注释进行注释的方法和对类、接口进行注释的方法一样。所不同的是,J2SE5.0为注释单独提供了4种注释。它们是Target、 Retention、Documented和Inherited。下面就分别介绍这4种注释。

   Target
   这个注释理解起来非常简单。由于target的中文意思是“目标”,因此,我们可能已经猜到这个注释和某一些目标相关。那么这些目标是指什么呢?大家可以先看看下面的代码。

            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->@Target( ... ElementType.METHOD ) @interface MyAnnotation ... {} @MyAnnotation // 错误的使用 public class Class1 ... { @MyAnnotation // 正确的使用 public void myMethod1() ... {} }
    以上代码定义了一个注释MyAnnotation和一个类Class1,并且使用MyAnnotation分别对Class1和myMethod1进行注 释。如果编译这段代码是无法通过的。也许有些人感到惊讶,没错啊!但问题就出在@Target(ElementType.METHOD)上,由于 Target使用了一个枚举类型属性,它的值是ElementType.METHOD。这就表明MyAnnotation只能为方法注释。而不能为其它的 任何语言元素进行注释。因此,MyAnnotation自然也不能为Class1进行注释了。
  
说到这,大家可能已经基本明白了。原来target所指的目标就是java的语言元素。如类、接口、方法等。当然,Target还可以对其它的语言元素进行限制,如构造函数、字段、参数等。如只允许对方法和构造函数进行注释可以写成:

            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->@Target( ... {ElementType.METHOD, ElementType.CONSTRUCTOR} ) @interface MyAnnotation ... {}
Retention
     既然可以自定义注释,当然也可以读取程序中的注释(如何读取注释将在下一节中讨论)。但是注释只有被保存在class文件中才可以被读出来。而 Retention就是为设置注释是否保存在class文件中而存在的。下面的代码是Retention的详细用法。

            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->@Retention(RetentionPolicy.SOURCE) @interface MyAnnotation1 ... { } @Retention(RetentionPolicy.CLASS) @interface MyAnnotation2 ... {} @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation3 ... {}
    其中第一段代码的作用是不将注释保存在class文件中,也就是说象“//”一样在编译时被过滤掉了。第二段代码的作用是只将注释保存在 class文件中,而使用反射读取注释时忽略这些注释。第三段代码的作用是即将注释保存在class文件中,也可以通过反射读取注释。

Documented

    这个注释和它的名子一样和文档有关。在默认的情况下在使用javadoc自动生成文档时,注释将被忽略掉。如果想在文档中也包含注释,必须使用Documented为文档注释。
            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->@interface MyAnnotation ... { } @MyAnnotation class Class1 ... { public void myMethod() ... { } }
使用javadoc为这段代码生成文档时并不将@MyAnnotation包含进去。生成的文档对Class1的描述如下:
            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->class Class1extends java.lang.Object 而如果这样定义MyAnnotation将会出现另一个结果。 @Documented @interface MyAnnotation ... {} 生成的文档: @MyAnnotation // 这行是在加上@Documented后被加上的 class Class1extends java.lang.Object
Inherited

     继承是java主要的特性之一。在类中的protected和public成员都将会被子类继承,但是父类的注释会不会被子类继承呢?很遗憾的告诉大家, 在默认的情况下,父类的注释并不会被子类继承。如果要继承,就必须加上Inherited注释。
            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->@Inherited @interface MyAnnotation ... { } @MyAnnotation public class ParentClass ... {} public class ChildClass extends ParentClass ... { } 在以上代码中ChildClass和ParentClass一样都已被MyAnnotation注释了。

五、如何使用反射读取注释

    前面讨论了如何自定义注释。但是自定义了注释又有什么用呢?这个问题才是J2SE5.0提供注释的关键。自定义注释当然是要用的。那么如何用呢?解决这个问题就需要使用java最令人兴奋的功能之一:反射(reflect)。
在以前的JDK版本中,我们可以使用反射得到类的方法、方法的参数以及其它的类成员等信息。那么在J2SE5.0中同样也可以象方法一样得到注释的各种信息。

    在使用反射之前必须使用import java.lang.reflect.* 来导入和反射相关的类。
    如果要得到某一个类或接口的注释信息,可以使用如下代码:

Annotation annotation = TestAnnotation.class.getAnnotation(MyAnnotation.class);

如果要得到全部的注释信息可使用如下语句:
Annotation[] annotations = TestAnnotation.class.getAnnotations();

Annotation[] annotations = TestAnnotation.class.getDeclaredAnnotations();

getDeclaredAnnotations与getAnnotations类似,但它们不同的是getDeclaredAnnotations得到的 是当前成员所有的注释,不包括继承的。而getAnnotations得到的是包括继承的所有注释。

    如果要得到其它成员的注释,可先得到这个成员,然后再得到相应的注释。如得到myMethod的注释。

            
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ -->Method method = TestAnnotation. class .getMethod( " myMethod " , null ); Annotation annotation = method.getAnnotation(MyAnnotation. class ); 注:要想使用反射得到注释信息,这个注释必须使用 @Retention(RetentionPolicy.RUNTIME)进行注释。

总结
    注释是J2SE5.0提供的一项非常有趣的功能。它不但有趣,而且还非常有用。EJB3规范就是借助于注释实现的。这样将使EJB3在实现起来更简单,更 人性化。还有Hibernate3除了使用传统的方法生成hibernate映射外,也可以使用注释来生成hibernate映射。总之,如果能将注释灵 活应用到程序中,将会使你的程序更加简洁和强大。

分享到:
评论

相关推荐

    java高手真经 光盘源码

    java高手真经 全光盘源代码 打包rar 第1部分(2个程序包) HelloWorld.zip 01.Java入门样例HelloWorld demo.zip 03.Eclipse入门样例demo 第2部分(3个程序包) ...javafeature.zip 29.Java5.0语言新特性

    Java高手真经(编程基础卷)光盘全部源码 免积分

    看到那些要积分的很不酸,发布免费版本。 第1部分(2个程序包) HelloWorld.zip 01.Java入门样例HelloWorld demo.zip 03.Eclipse入门样例demo 第2部分(3个程序包) ...javafeature.zip 29.Java5.0语言新特性

    Java高手真经(编程基础卷)光盘全部源码

    看到很多人都分卷打包的,下载很是不方便,还浪费积分,我就整合压缩打包到一个包里面,里面包含全部源码 源码目录如下: 第1部分(2个程序包) HelloWorld.zip 01.Java入门...javafeature.zip 29.Java5.0语言新特性

    java或Java框架中常用的注解及其作用详解_资料.docx

    java或Java框架中常用的注解及其作用详解:Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制。 Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过...

    java基础案例与开发详解案例源码全

    2.3.4 Java代码中的注释23 2.3.5 常见错误解析24 2.4 Java类库组织结构和文档27 2.5 Java虚拟机简介28 2.6 Java技术两种核心运行机制29 2.7 上机练习30 第3章 3.1 变量32 3.1.1 什么是变量32 3.1.2 为什么需要变量32...

    JAVA2核心技术(中文的PDF).part3.rar

    包括:多线程、集合框架、网络API、数据库编程、分布式对象等,深入探究了Swing、Java 2D API、JavaBean、Java安全模式、XML、注释、元数据等主题,同时涉及本地方法、国际化以及JDK 5.0的内容。本书适合软件开发...

    asp.net知识库

    ASP.NET2.0 ObjectDataSource的使用详解(3) ASP.NET2.0 快速入门 ----默认中的主题外观 数据库开发 ADO.NET 通过DataTable获得表的主键 ADO.NET 2.0 操作实例 ADO.NET 2.0 大批量数据操作和多个动态的结果集 ADO...

Global site tag (gtag.js) - Google Analytics