一、什么是注释
说起注释,得先提一提什么是元数据(metadata)。所谓元数据就是数据的数据。也就是说,元数据是描述数据的。就象数据表中的字段一样,每个字段描 述了这个字段下的数据的含义。而J2SE5.0中提供的注释就是java源代码的元数据,也就是说注释是描述java源代码的。在J2SE5.0中可以自 定义注释。使用时在@后面跟注释的名字。
二、J2SE5.0中预定义的注释
在J2SE5.0的java.lang包中预定义了三个注释。它们是Override、Deprecated和SuppressWarnings。下面分别解释它们的含义。
Override
这个注释的作用是标识某一个方法是否覆盖了它的父类的方法。那么为什么要标识呢?让我们来看看如果不用Override标识会发生什么事情。
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> class ParentClass1 { public void myMethod1() {...} } class Class1 extends ParentClass1 { public void myMethod2() {...} }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> ParentClass1 c1 = new Class1(); c1.myMethod1();
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> class Class1 extends ParentClass1 { @Override // 编译器产生一个错误 public void myMethod2() {...} }
<!-- 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() {} }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> public void myMethod() { List wordList = new ArrayList(); wordList.add( " foo " ); }
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 { }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> public @interface MyAnnotation { String value(); }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @MyAnnotation("abc") public void myMethod() { }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> public @interface MyAnnotation { public String myMethod() {} default “xyz”; }
<!-- 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() { }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @Target( ElementType.METHOD ) @interface MyAnnotation {} @MyAnnotation // 错误的使用 public class Class1 { @MyAnnotation // 正确的使用 public void myMethod1() {} }
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @Target( {ElementType.METHOD, ElementType.CONSTRUCTOR} ) @interface MyAnnotation {}
<!-- 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 {}
<!-- Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.com/ --> @interface MyAnnotation { } @MyAnnotation class Class1 { public void myMethod() { } }
<!-- 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
<!-- 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映射。总之,如果能将注释灵 活应用到程序中,将会使你的程序更加简洁和强大。